链接:https://www.nowcoder.com/acm/contest/139/D
来源:牛客网
同构图:假设G=(V,E)和G1=(V1,E1)是两个图,如果存在一个双射m:V→V1,使得对所有的x,y∈V均有xy∈E等价于m(x)m(y)∈E1,则称G和G1是同构的,这样的一个映射m称之为一个同构,如果G=G1,则称他为一个自同构。
题目描述
Two undirected simple graphs and where are isomorphic when there exists a bijection on V satisfying if and only if {x, y} ∈ E2.Given two graphs and , count the number of graphs satisfying the following condition:
* .
* 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的同构图
解析 点的数量是8我们不能用边来枚举子图 数量太多了 我们可以把点全排列按照映射的关系去找边是否存在 再把重复的去掉就是答案
去重可以用二进制压缩边集set去重,也可以哈希,除以自同构数量,暴力。。。。
自同构数求法 枚举全排列映射到本身g1 如果图完全一样 计下数。
代码:
#include<bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f,maxn=10,mod=1e9+7; typedef long long ll; int n,m1,m2,u[maxn*10],v[maxn*10],g1[maxn][maxn],g2[maxn][maxn],a[maxn]; int main() { while(scanf("%d%d%d",&n,&m1,&m2)!=EOF) { memset(g1,0,sizeof(g1)); memset(g2,0,sizeof(g2)); 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; } 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 ",ans/num); } return 0; } //5 3 7 //1 2 //1 3 //1 4 //1 2 //1 3 //1 4 //2 4 //3 4 //4 5 //2 5
暴力版 就是先存下一个同构图temp 在所有的里面找与temp行列式完全相同的有多少个 就是自同构的数量
#include<bits/stdc++.h>
using namespace std;
const int maxn=10,mod=1e9+7;
typedef long long ll;
int g1[maxn][maxn],g2[maxn][maxn],g3[maxn][maxn];
int a[maxn],temp[maxn][maxn];
int main()
{
int n,m1,m2;
while(cin>>n>>m1>>m2)
{
int x,y;
memset(g1,0,sizeof(g1));
memset(g2,0,sizeof(g2));
for(int i=0;i<m1;i++)
{
cin>>x>>y;
g1[x][y]=g1[y][x]=1;
}
for(int i=0;i<m2;i++)
{
cin>>x>>y;
g2[x][y]=g2[y][x]=1;
}
for(int i=1;i<=n;i++)a[i]=i;
do{
int flag=0;
memset(temp,0,sizeof(temp));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(g1[i][j]==1)
{
if(g2[a[i]][a[j]]==0)
{
flag=1;break;
}
else
temp[a[i]][a[j]]=1;
}
}
if(flag)break;
}
if(!flag)break;
}while(next_permutation(a+1,a+n+1));
for(int i=1;i<=n;i++)a[i]=i;
int ans=0,num=0;
do{
int flag=0;
memset(g3,0,sizeof(g3));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(g1[i][j]==1)
{
if(g2[a[i]][a[j]]==0)
{
flag=1;break;
}
else
g3[a[i]][a[j]]=1;
}
}
if(flag)break;
}
if(!flag)
{
ans++;
for(int i=1;i<=n;i++)//{
for(int j=1;j<=n;j++)
if(temp[a[i]][a[j]]!=g3[a[i]][a[j]])flag=1;
if(!flag)num++;
}
}while(next_permutation(a+1,a+n+1));
//cout<<ans<<" "<<num<<endl;
cout<<ans/num<<endl;
}
}
J题 区间之外不同数的个数 复制数组 主席树 过的 正解是 离线+树状数组 记录下第一次出现和最后一次出现的位置
代码
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 2e5 + 100; int n,q; int cnt = 0; struct Node { int l,r,sum; } p[maxn*200]; int la[maxn]; int a[maxn]; int root[maxn]; int build(int l,int r) { int nc = ++cnt; p[nc].sum = 0; p[nc].l = p[nc].r = 0; if (l == r) return nc; int m = l + r >> 1; p[nc].l = build(l,m); p[nc].r = build(m+1,r); return nc; } int update(int pos,int c,int v,int l,int r) { int nc = ++cnt; p[nc] = p[c]; p[nc].sum += v; if (l == r) return nc; int m = l+r>>1; if (m >= pos) { p[nc].l = update(pos,p[c].l,v,l,m); } else { p[nc].r = update(pos,p[c].r,v,m+1,r); } return nc; } int query(int pos,int c,int l,int r) { if (l == r) return p[c].sum; int m = l + r >> 1; if (m >= pos) { return p[p[c].r ].sum + query(pos,p[c].l,l,m); } else return query(pos,p[c].r,m+1,r); } int main() { while(scanf("%d%d",&n,&q)!=EOF) { memset(la,-1,sizeof la); cnt=0; for (int i = 1; i <= n; ++i) { scanf("%d",a+i); } for(int i=n+1; i<=2*n; i++) a[i]=a[i-n]; n=n*2; root[0] = build(1,n); for (int i = 1 ; i <= n; ++i) { int v = a[i]; if (la[v] == -1) { root[i] = update(i,root[i-1],1,1,n); } else { int t = update(la[v],root[i-1],-1,1,n); root[i] = update(i,t,1,1,n); } la[v] = i; } while(q--) { int x,y; scanf("%d %d",&x, &y); printf("%d ",query(y,root[n/2+x],1,n)); } } }