最后要求一一对应,很难限制,相当于限制某些点没有被对应一个也不成立。但是其反面某些点不能被对应可以随便做,对这个容斥即可。可能需要稍微卡一下常数?
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define N 20
#define M N<<1
#define lint long long
using namespace std;
struct edges{
int to,pre;
}e[M];int h[N],etop,con[N][N],a[N];
lint dp[N][N],tmp[N];int n,c;
inline int add_edge(int u,int v)
{ return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
int dfs(int x,int fa)
{
for(int i=1;i<=c;i++) dp[x][a[i]]=1ll;
for(int i=h[x],y;i;i=e[i].pre)
if((y=e[i].to)^fa) dfs(y,x);
for(int i=h[x],y;i;i=e[i].pre)
if((y=e[i].to)^fa)
rep(j,1,c)
{
lint tmp=0ll;
rep(k,1,c) if(con[a[j]][a[k]]) tmp+=dp[y][a[k]];
dp[x][a[j]]*=tmp;
}
return 0;
}
lint calc(int n)
{
int all=(1<<n)-1;lint ans=0ll;
for(int i=0,s;i<=all;++i)
{
c=0,s=n;
for(int j=1;j<=n;++j)
if((i>>(j-1))&1) a[++c]=j,s--;
s=((s&1)?-1:1),dfs(1,0);
for(int j=1;j<=c;++j) ans+=s*dp[1][a[j]];
}
return ans;
}
int main()
{
int m;scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;scanf("%d%d",&u,&v);
con[u][v]=con[v][u]=true;
}
for(int i=1;i<n;i++)
{
int u,v;scanf("%d%d",&u,&v);
add_edge(u,v),add_edge(v,u);
}
return !printf("%lld\n",calc(n));
}