列表

详情


NC20521. [ZJOI2016]小星星

描述

小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星。有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了n-1条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连, 那么要求对应的小星星原来的图纸上也有细线相连。小Y想知道有多少种可能的对应方式。只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。

输入描述

第一行包含个2正整数n,m,表示原来的饰品中小星星的个数和细线的条数。
接下来m行,每行包含2个正整数u,v,表示原来的饰品中小星星u和v通过细线连了起来。这里的小星星从1开始标号。保证u≠v,且每对小星星之间最多只有一条细线相连。
接下来n-1行,每行包含个2正整数u,v,表示现在的饰品中小星星u和v通过细线连了起来。保证这些小星星通过细线可以串在一起。
n ≤ 17,m ≤ n*(n-1)/2

输出描述

输出共1行,包含一个整数表示可能的对应方式的数量。如果不存在可行的对应方式则输出0。

示例1

输入:

4 3
1 2
1 3
1 4
4 1
4 2
4 3

输出:

6

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 432ms, 内存消耗: 420K, 提交时间: 2023-02-14 18:39:57

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#define ll long long
#define reg register
#define fo(a,b,c) for(reg ll a=b;a<=c;a++)
#define re(a,b,c) for(reg ll a=b;a>=c;a--)
#define pb push_back
#define mp make_pair
#define pii pair<ll,ll>
#define fi first
#define se second
#define mod 998244353
using namespace std;
inline ll gi(){
    ll x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
ll n;
vector<ll> g[20];
ll dp[20][20],a[20][20];
ll tmp[20],cnt;
void dfs(ll u,ll fa,ll s)
{
	fo(i,1,cnt) dp[u][tmp[i]]=1;
	for(ll v:g[u])
	{
		if(v==fa) continue;
		dfs(v,u,s);
		fo(i,1,cnt)
		{
			ll sum=0;
			fo(j,1,cnt)
			{
				if(a[tmp[i]][tmp[j]])
				{
					sum+=dp[v][tmp[j]];
				}
			}
			dp[u][tmp[i]]*=sum;
		}
	}
}
int main()
{
	n=gi();
	ll m=gi();
	fo(i,1,m)
	{
		ll x=gi(),y=gi();
		a[x][y]=1;
		a[y][x]=1;
	}
	fo(i,1,n-1)
	{
		ll x=gi();
		ll y=gi();
		g[x].pb(y);
		g[y].pb(x);
	}
	ll ans=0;
	fo(i,0,(1<<n)-1)
	{
		cnt=0;
		fo(j,1,n)
		{
			if(i&(1<<j-1))
			{
				cnt++;
				tmp[cnt]=j;
			}
		}
		dfs(1,0,i);
		ll sum=0;
		fo(k,1,cnt)
		{
			sum+=dp[1][tmp[k]];
		}
		if(n-cnt&1) ans-=sum;
		else ans+=sum;
	}
	cout<<ans;
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 288ms, 内存消耗: 504K, 提交时间: 2020-03-28 23:26:22

#include<bits/stdc++.h>
using namespace std;

#define ll long long 
int mp[20][20];
vector<int>G[20];

ll dp[20][20],tttt[20];
int n,m;

int cnt=0;
vector<int>tmp;
void dfs(int x,int fa)
{
	for(int i=0;i<n;i++) dp[x][i]=1;
	for(int v:G[x])
	{
		if(v==fa) continue;
		dfs(v,x);
		for(int i=1;i<=cnt;i++) tttt[tmp[i]]=0;
		for(int i=1;i<=cnt;i++)
		{
			for(int j=1;j<=cnt;j++)
			{
				tttt[tmp[i]]+=mp[tmp[i]][tmp[j]]*dp[x][tmp[i]]*dp[v][tmp[j]];//转移 
			} 
		}
		for(int i=1;i<=cnt;i++) dp[x][tmp[i]]=tttt[tmp[i]];
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		cin>>x>>y;
		x--,y--;
		mp[x][y]=mp[y][x]=1;
	}
	for(int i=1;i<n;i++)
	{
		int x,y;
		cin>>x>>y;
		G[x].push_back(y);
		G[y].push_back(x);
	}
	tmp.resize(n+2); 
	ll ans=0;
	for(int i=0;i<1<<n;i++)
	{
		memset(dp,0,sizeof dp);
		cnt=0;
		for(int j=0;j<n;j++) if(i>>j&1) tmp[++cnt]=j;
		dfs(1,0);
		ll res=0;
		for(int i=1;i<=cnt;i++) res+=dp[1][tmp[i]];
		if((n-cnt)&1) ans-=res;
		else ans+=res;
	} 
	cout<<ans<<endl;
	return 0;
}

上一题