牛客网暑期ACM多校训练营(第一场) D Two Graphs(图的同构)
题目大意:给你两个图 G1 G2,让你在G2中找有多少个子图与G1 同构
题目分析
首先这个题目的数据量非常小 n=8 ,所以我们可以采取非常暴力的做法,由于G2中如果有点与G1同构的话,我们发现只要改变G2中 点的序号,此时的新图中如果有一部分与G1完全相同,那么这些点构成的图就会与G1同构。这样我们可以对G2中的点进行全排列,判断G1中存在的边的位置,新的G2中是否也存在同样的边即可
然而,直接找next_permutation 会存在重复,比如说,G1中需要的点的位置都没有变,剩下的点位置发生变化,这样也是一组新的排列,这样会导致我们重复计算,我们用一个map来处理这个情况,我们将g2中的边每个边给不同的序号,如果我们找到了一组点的排列,将这一组的信息储存到b变量中,这样再通过map查询是否存在就可以删去重复了
代码:
#include <bits/stdc++.h>
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
int n,m1,m2;
int g[20][20];
int t[20][20];
int a[20];
map<int,int>mp;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>n>>m1>>m2)
{
cl(g);
cl(t);
mp.clear();
for(int i=1;i<=m1;i++)
{
int x,y;
cin>>x>>y;
g[x][y]=1;
g[y][x]=1;
}
for(int i=1;i<=m2;i++)
{
int x,y;
cin>>x>>y;
t[x][y]=t[y][x]=i;
}
int cnt=0;
for(int i=1;i<=n;i++) a[i]=i;
do
{
int flag=1;
int b=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(g[i][j])
{
if(t[a[i]][a[j]]==0)flag=0;
else b|=1<<t[a[i]][a[j]];
}
}
}
if(flag&&mp[b]==0)
{
mp[b]=1;
cnt++;
}
}while(next_permutation(a+1,a+1+n));
cout<<cnt<<endl;
}
return 0;
}