牛客网暑期ACM多校训练营(第一场)D. Two Graphs 图论 枚举全排列

题目链接:D. Two Graphs

题目大意

两张图G1和G2, 最多只有8个节点, 两个节点之间最多有一条边, 两张图节点个数都为n, 边数为m1和m2
求由多少种方案, 从G2中选出m1条边, 使得G1和G2重构

思路

枚举n个节点的全排列, 就是将G2中节点和G1的节点一一对应起来, 一共由n!中对应方案, 判断每一种方案是否可行, 如果可行, 那将方案用一个unsigned long long保存起来(最多8x8条边, 64位每位对应一条边), 然后放进一个set里去重, 最后set的size就是答案

代码

语言:C++14 代码长度:1073 运行时间: 40 ms 占用内存:864K 运行结果:答案正确

#include <bits/stdc++.h>

using namespace std;
typedef unsigned long long ull;
const int maxn = 20;
int n, m1, m2;
int G1[maxn][maxn], G2[maxn][maxn];
int x[maxn];

int main()
{
    while(cin >> n >> m1 >> m2)
    {
        memset(G1, 0, sizeof(G1));
        memset(G2, 0, sizeof(G1));
        for(int i=1; i<=n; ++i) x[i] = i;
        int a, b;
        for(int i=0; i<m1; ++i)
        {
            cin >> a >> b;
            G1[a][b] = 1;
            G1[b][a] = 1;
        }
        for(int i=0; i<m2; ++i)
        {
            cin >> a >> b;
            G2[a][b] = 1;
            G2[b][a] = 1;
        }
        set<ull> S;
        do
        {
            bool flag = 0;
            ull t = 0;
            for(int i=1; i<=n; ++i)
            {
                for(int j=i+1; j<=n; ++j)
                {
                    if(G1[i][j]==1 && G2[x[i]][x[j]] == 0)
                    {
                        flag = 1;
                        break;
                    }
                    else
                    {
                        if(G1[i][j])
                        {
                            int xx = x[i];
                            int yy = x[j];
                            if(xx>yy) swap(xx, yy);

                            t |= ((ull)1 << (xx*n+yy));
                        }
                    }
                }
                if(flag) break;
            }
            if(!flag) S.insert(t);//, cout << t << "**" << endl;
        }while(next_permutation(x+1, x+1+n));
        cout << S.size() << endl;
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/litmxs/article/details/81121080
今日推荐