Description
两个无向简单图G1=<V,E1>,G2=<V,E2>G1=<V,E1>,G2=<V,E2>同构表示存在一个VV之间的双射使得(x,y)∈E1(x,y)∈E1当且仅当(ϕ(x),ϕ(y))∈E2(ϕ(x),ϕ(y))∈E2. 现给出两个图G1=<V,E1>,G2=<V,E2>G1=<V,E1>,G2=<V,E2>,统计图G=<V,E>G=<V,E>的数量,使其满足E⊂E2E⊂E2且G1G1和GG同构
Input
多组用例,每组用例首先输入三个整数表示点数和两个图的边数,之后m1m1行输入图G1G1的m1m1条边,最后m2m2行输入图G2G2的m2m2条边
(1≤n≤8,1≤m1≤m2≤n(n−1)2)(1≤n≤8,1≤m1≤m2≤n(n−1)2)
Output
输出满足条件的图GG的个数
Sample Input
3 1 2
1 3
1 2
2 3
4 2 3
1 2
1 3
4 1
4 2
4 3
Sample Output
2
3
Solution
该种同构本质上是对点的重排,故枚举所有点编号的排列,得到G1G1转化编号后的图后判断其是否为G2G2子图即可,但是注意到由于自同构的存在,以上求出的很多方案本质对应的是一个图,故在求出所有满足条件的排列方案数量后,除去自同构数量即为答案
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m1,m2,u[100],v[100],g1[10][10],g2[10][10],a[10];
int main()
{
while(~scanf("%d%d%d",&n,&m1,&m2))
{
memset(g1,0,sizeof(g1));
for(int i=1;i<=m1;i++)
{
scanf("%d%d",&u[i],&v[i]);
g1[u[i]][v[i]]=g1[v[i]][u[i]]=1;
}
memset(g2,0,sizeof(g2));
for(int i=1;i<=m2;i++)
{
int x,y;
scanf("%d%d",&x,&y);
g2[x][y]=g2[y][x]=1;
}
for(int i=1;i<=n;i++)a[i]=i;
int ans=0,num=0;
do
{
int flag1=1,flag2=1;
for(int i=1;i<=m1;i++)
{
int x=a[u[i]],y=a[v[i]];
if(!g1[x][y])flag1=0;
if(!g2[x][y])flag2=0;
}
ans+=flag2;
num+=flag1;
}while(next_permutation(a+1,a+n+1));
printf("%d\n",ans/num);
}
return 0;
}