NC20521. [ZJOI2016]小星星
描述
输入描述
第一行包含个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; }