小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。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read()
{
int 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*10+ch-‘0‘; ch=getchar();}
return x*f;
}
#define LL long long
#define MAXN 50
int N,M;
struct EdgeNode{int next,to;}edge[MAXN<<1];
int head[MAXN],cnt=1;
void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
LL dp[MAXN][MAXN],ans,now,tmp;
int lt[MAXN][MAXN],bin[MAXN],tot,a[MAXN];
void DFS(int now,int last)
{
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last) DFS(edge[i].to,now);
for (int i=1; i<=tot; i++)
{
dp[now][i]=1;
for (int j=head[now]; j; j=edge[j].next)
if (edge[j].to!=last)
{
tmp=0;
for (int k=1; k<=tot; k++)
if (lt[a[k]][a[i]]) tmp+=dp[edge[j].to][k];
dp[now][i]*=tmp;
}
}
}
int main()
{
N=read(),M=read();
for (int x,y,i=1; i<=M; i++) x=read(),y=read(),lt[x][y]=lt[y][x]=1;
for (int x,y,i=1; i<=N-1; i++) x=read(),y=read(),InsertEdge(x,y);
bin[0]=1; for (int i=1; i<=N; i++) bin[i]=bin[i-1]<<1;
for (int i=1; i<=bin[N]-1; i++)
{
now=0; tot=0;
for (int j=1; j<=N; j++) if (i&bin[j-1]) a[++tot]=j;
DFS(1,0);
for (int j=1; j<=tot; j++) now+=dp[1][j];
if ((tot&1)==(N&1)) ans+=now; else ans-=now;
}
printf("%lld\n",ans);
return 0;
}