2018牛客网暑期ACM多校训练营(第一场)D图同构,J

链接: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\n",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\n",query(y,root[n/2+x],1,n));
        }
 
    }
}

 

 

posted @ 2018-07-20 16:19  灬从此以后灬  阅读(439)  评论(0编辑  收藏  举报