2018牛客网暑期ACM多校训练营(第一场) D - Two Graphs - [无向图同构]
题目链接:https://www.nowcoder.com/acm/contest/139/D
题目描述
Two undirected simple graphsGiven two graphs
*
* G1 and G are isomorphic.
输入描述:
The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains three integers n, m1 and m2 where |E1| = m1 and |E2| = m2.
The i-th of the following m1 lines contains 2 integers ai and bi which denote {ai, bi} ∈ E1.
The i-th of the last m2 lines contains 2 integers ai and bi which denote {ai, bi} ∈ E2.
输出描述:
For each test case, print an integer which denotes the result.
输入
3 1 2 1 3 1 2 2 3 4 2 3 1 2 1 3 4 1 4 2 4 3
输出
2 3
备注:
* 1 ≤ n ≤ 8
*
* 1 ≤ ai,bi ≤ n
* The number of test cases does not exceed 50.
题意:
两个简单无向图G1和G2,问G2的子图中有多少个与G1同构。
题解:
显然枚举子图不现实,假设phi(x)是从G1中的某个点映射到G2的某个点的函数,
那么,从最开始 phi[1:n] = (1,2,3,…,n) 开始全排列,可以枚举出G1对应到G2的全部情况,只要判断G2中有没有相应的边即可。
同时,要考虑自同构的情况,通过G1映射到自身判断是否自同构,最后答案除以自同构数即可。
AC代码:
#include<bits/stdc++.h> using namespace std; const int maxn=10; const int maxm=maxn*(maxn-1)/2; int n,m1,m2; int E1[maxn][maxn],u[maxm],v[maxm]; int E2[maxn][maxn]; int phi[maxn]; int main() { while(scanf("%d%d%d",&n,&m1,&m2)!=EOF) { memset(E1,0,sizeof(E1)); memset(E2,0,sizeof(E2)); for(int i=1;i<=m1;i++) //G1 { scanf("%d%d",&u[i],&v[i]); E1[u[i]][v[i]]=E1[v[i]][u[i]]=1; } for(int i=1,a,b;i<=m2;i++) //G2 { scanf("%d%d",&a,&b); E2[a][b]=E2[b][a]=1; } for(int i=1;i<=n;i++) phi[i]=i; //初始化映射函数 int ans=0,cnt=0; do { bool ok=1; //标记是否与G2的某个子图同构 bool self=1; //标记是否自同构 for(int i=1;i<=m1;i++) { int a=phi[u[i]],b=phi[v[i]]; if(E2[a][b]==0) ok=0; if(E1[a][b]==0) self=0; } if(ok) ans++; if(self) cnt++; }while(next_permutation(phi+1,phi+n+1)); printf("%d\n",ans/cnt); } }
转载请注明出处:https://dilthey.cnblogs.com/