zoukankan      html  css  js  c++  java
  • P1330 封锁阳光大学

    题目传送门

    一、二分图着色原理

    二、dfs深度优先遍历解法

    #include <bits/stdc++.h>
    
    using namespace std;
    
    //dfs代码简短一些,注意第29行。
    const int N = 1e4 + 10;     //题目中说结点数最大10^4=1e4
    const int M = 1e5 * 2 + 10; //边数上限,因为是无向图,所以记录两次,就是1e5*2
    
    //链式前向星
    struct Edge {
        int to, next;
    } e[M];
    int head[N], idx;
    
    void add(int u, int v) {
        e[++idx].to = v;
        e[idx].next = head[u];
        head[u] = idx;
    }
    
    int n, m, ans, ans1, ans2;
    int color[N];     //上色结果
    
    /**
     * 功能:对二分图进行上色
     * @param u 要上色的结点
     * @param c 上一个过来结点的颜色
     */
    void dfs(int u, int c) {
        //上一个结点颜色是1,那么u就是2
        if (c == 1) color[u] = 2, ans2++;
            //上一个结点颜色是2,那么u就是1
        else if (c == 2) color[u] = 1, ans1++;
        //遍历每个出边
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].to;
            //如果已上色
            if (color[v] > 0) {
                //颜色与上一个结点的颜色一样,那么就是冲突
                if (color[v] == color[u]) {
                    printf("Impossible");
                    exit(0);
                }
            }//未上色,则进行上色即可
            else dfs(v, color[u]);
        }
    }
    
    int main() {
        cin >> n >> m;
        int x, y;
        for (int i = 1; i <= m; ++i) {
            cin >> x >> y;
            add(x, y), add(y, x);//无向图,双向创建
        }
        //寻找每个结点,如果没有染过颜色,就深度优先开始染色
        for (int i = 1; i <= n; ++i)
            if (!color[i]) {
                //每一轮用之前清空为零
                ans1 = ans2 = 0;
                dfs(i, 1);//假设第一个结点是颜色1
                //两种颜色哪个少哪个是答案
                ans += min(ans1, ans2);
            }
        //如果有解,那么输出
        printf("%d", ans);
        return 0;
    }
    

    三、bfs广度优先遍历解法

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e4 + 10; //题目中说结点数最大10^4=1e4
    const int M = 1e5 * 2 + 10; //边数上限,因为是无向图,所以记录两次,就是1e5*2
    /*
    根据题意可知二分图染色。若无法被染成二分图,输出Impossible;
    反之,对于每个二分图,记录两种颜色的点的个数,取min后记录答案中。
    
    注意,图可能不连通。因此对于每个二分图,都要进行取min操作,而不是对整个图染色后取min。
    */
    
    int color[N]; //0:未上色,1:黑色,2:白色
    int n, m, ans;
    
    //广度优先搜索的队列
    queue<int> q;
    
    //链式前向星
    struct Edge {
        int to, next;
    } edge[M];
    
    int idx, head[N];
    
    void add(int u, int v) {
        edge[++idx].to = v;
        edge[idx].next = head[u];
        head[u] = idx;
    }
    
    //广度优先搜索
    int bfs(int a) {
        int ans1 = 0, ans2 = 0;
        color[a] = 1;
        ans1++;
        q.push(a);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i; i = edge[i].next) {
                int v = edge[i].to;
                //目标点未着色
                if (color[v] == 0) {
                    //来源点是黑的,那么目标点是白的
                    if (color[u] == 1) color[v] = 2, ans2++;
                    //来源点是白的,那么目标点是黑的
                    else if (color[u] == 2) color[v] = 1, ans1++;
                    q.push(v);
                } else
                    //如果已着色,那么需要判断和现在的要求是不是有冲突:
                    if (color[v] == color[u]) {//相临的存在冲突
                    printf("Impossible");
                    exit(0);
                }
            }
        }
        //哪个小就用哪个
        return min(ans1, ans2);
    }
    
    int main() {
        //n个结点,m条边
        cin >> n >> m;
        //m条边
        for (int i = 1; i <= m; ++i) {
            int x, y;
            cin >> x >> y;
            add(x, y), add(y, x); //无向图双向建边,题目中明显说是无向图!
        }
        //注意,图可能不连通。因此对于每个二分图,都要进行取min操作,
        //而不是对整个图染色后取min。
        //这里有一个小技巧,就是遍历每个结点,如果此结点没有上过色,就表示是一个独立的图,需要单独计算
        for (int i = 1; i <= n; ++i)
            if (!color[i]) ans += bfs(i);
    
        //输出
        printf("%d", ans);
        return 0;
    }
    
  • 相关阅读:
    Gem命令详解
    使用Ruby脚本部署Redis Cluster集群
    解决gem install redis报错
    Redis Cluster命令安装
    Redis Sentinel原理介绍与部署
    PyCharm单行多行代码注释快捷键
    windows下python安装与卸载
    MySQL通过SQL语句查看表的索引
    Redis主从复制
    MySQL开启binlog日志
  • 原文地址:https://www.cnblogs.com/littlehb/p/15137826.html
Copyright © 2011-2022 走看看