• 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
    ",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));
            }
     
        }
    }
    
    
    
     

  • 相关阅读:
    Android Studio3.1.2编译时Java Compiler出错:Warning: Failed to parse host proxy3.bj...
    Android RxJava 2 的用法 just 、from、map、subscribe、flatmap、Flowable、Function、Consumer ...【转】
    Android DevArt6:Android中IPC的六种方式
    Android 深入浅出
    Eclipse代码自动补全
    Android 深入浅出
    Android 深入浅出
    Android中查看SQLite中字段数据的两种方式
    Android Studio 打包时 Signature Version 选择V1还是V2 ?
    Android进阶AIDL
  • 原文地址:https://www.cnblogs.com/stranger-/p/9342125.html
Copyright © 2020-2023  润新知