zoukankan      html  css  js  c++  java
  • Codeforces #454 div1 C party(状态压缩bfs)

    题意:
    给你N个点的一幅图,初始图中有M条边,每次操作可以使得一个点连接的所有点变成一个团,问你最少多少次操作可以使得整个图变成一个团.

    解法:
    因为N很小 所以我们可以二进制压缩来表示一个点与其他点之间的关系。二进制的第i位代表标号位i+1的人。例如标号为1的人认识标号为3与5还有7的人,标号为1的二进制压缩结果就为0000000000000000001010101(标号为i的人肯定认识他自身)。

    //https://www.cnblogs.com/FxxL/p/8095418.html
    #include <iostream>
    #include <string.h>
    #include <cmath>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    using namespace std;
    const int maxn = (1 << 22), maxm = 30;
    
    int n, m;
    int dp[maxn + 50], key[maxn + 50], str[maxn + 50];
    int a[maxm], num;
    queue<int> q;
    
    void bfs()
    {
        int now, tmp;
        while (!q.empty())
        {
            now = q.front(); q.pop();
            if (now == ((1 << n) - 1))
                return;
            for (int i = 0; i < n; i++) {
                if (now&(1 << i)) {//当前的数的第i位是1,也就是朋友i可以做介绍
                    tmp = now | a[i];
                    if (dp[tmp] == 0) {//出现的是没有记录过的数
                        dp[tmp] = dp[now] + 1;
                        key[tmp] = i;//记录更新到tmp的状态是通过i做介绍得来的
                        str[tmp] = now;//记录tmp的是now通过i做介绍得来的,用来记录路径。
                        q.push(tmp);
                    }
                }
            }
        }
    }
    
    int main()
    {
        int x, y, tmp;
        scanf("%d%d", &n, &m);//n个人
        memset(a, 0, sizeof(a));
        memset(dp, 0, sizeof(dp));
        memset(key, -1, sizeof(key));
        memset(str, -1, sizeof(str));
        for (int i = 0; i < n; i++) {
            a[i] |= (1 << i);//第i个人肯定认识他自己
        }
        for (int i = 1; i <= m; i++)
        {
            scanf("%d%d", &x, &y);
            x--, y--;
            a[x] |= (1 << y);   //更新每个人与其他人的关系,如果认识就给那一位的人标为1
            a[y] |= (1 << x);
        }
        for (int i = 0; i<n; i++)
        {
            dp[a[i]] = 1;
            key[a[i]] = i;
            q.push(a[i]);
        }
        if (m == n*(n - 1) / 2)
        {
            printf("0
    ");
            return 0;
        }
        bfs();
        tmp = (1 << n) - 1;
        //回溯求解
        while (tmp != -1)
        {
            ++num;
            tmp = str[tmp];
        }
        printf("%d
    ", num);
        return 0;
    }
  • 相关阅读:
    Java I/O(二 使用)
    Java 基本I/O的学习总结(一 是什么)
    设计模式(一)
    浏览器输入一个网址(发生的过程)
    final关键字的4种用法
    JavaScript(4)——闭包与this对象以及window对象
    JavaScript(3)—— 正则表达式
    JavaScript(2)——对象属性、原型与原型链
    JavaScript(1)——变量、函数声明及作用域
    构建分布式配置中心阿波罗(Apollo)
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/9489833.html
Copyright © 2011-2022 走看看