zoukankan      html  css  js  c++  java
  • CF1354E Graph Coloring(二分图+背包)

    题意:

    (n) 个点 (m) 条边的无向图,对每个点染 ({1,2,3}) 的颜色,要求使得任意相邻的两个点绝对值之差为 (1),且染成 ({1,2,3}) 颜色的点数分别为 ({n_1,n_2,n_3})

    题解:

    可以发现点染 (1)(3) 是等价的,故可以将问题先转化为二分图判定。
    注意图不一定是连通的,所以对所有连通块进行二分图判定,如果有一个连通块不是二分图就是 NO。
    之后问题就变成,给一个或多个是二分图的连通块,取每个二分图的左部或右部的点(一定要选一边)全部染成 (2) 能否刚好染够 (n_2),剩下一边 (1,3) 贪心染就好了。
    类似于背包,设 (dp[i][j]) 表示前 (i) 个连通块,每个连通块选左部或右部染色,是否能染 (j) 个点为 (2)
    转移:用 (c[i][0/1]) 表示 (i) 连通块左部或右部的大小,则
    (dp[i][j] = 1, if(dp[i-1][j-c[i][0]] == 1))
    (dp[i][j] = 1, if(dp[i-1][j-c[i][1]] == 1))
    (dp[连通块数目][n_2])(1) 时有解,否则无解。
    输出解就是背包记录路径问题。
    时间复杂度 (O(n^2))

    #include <bits/stdc++.h>
    using namespace std;
    
    #define debug(x) cerr << #x << " is " << x << '
    ';
    typedef long long LL;
    
    const int N = 5e3 + 5, M = 1e5 + 5, P = 1e9 + 7;
    
    int n, m, n1, n2, n3;
    int sz, vis[N], col[N], ans[N], which[N], c[N][2], dp[N][N], who[N][N];
    std::vector<int> g[N], r[N][2];
    
    void dfs(int u, int w) {
      vis[u] = 1, col[u] = w, c[sz][w]++;
      r[sz][w].push_back(u);
      for (auto v : g[u]) {
        if (vis[v]) {
          if (col[u] == col[v]) {
            cout << "NO" << '
    ';
            exit(0);
          }
        } else {
          dfs(v, w ^ 1);
        }
      }
    }
    
    int main() {
      ios::sync_with_stdio(false);
      cin.tie(0);
      cin >> n >> m;
      cin >> n1 >> n2 >> n3;
      for (int i = 1, u, v; i <= m; i++) {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
      }
      for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
          ++sz;
          dfs(i, 0);
        }
      }
      dp[0][0] = 1;
      for (int i = 1; i <= sz; i++) {
        for (int j = n2; j >= 0; j--) {
          if (j - c[i][0] >= 0 && dp[i - 1][j - c[i][0]]) {
            dp[i][j] = 1;
            who[i][j] = 0;
          }
          if (j - c[i][1] >= 0 && dp[i - 1][j - c[i][1]]) {
            dp[i][j] = 1;
            who[i][j] = 1;
          }
        }
      }
      if (!dp[sz][n2]) {
        cout << "NO" << '
    ';
      } else {
        for (int i = sz, all = n2; i >= 1; i--) {
          which[i] = who[i][all];
          all -= c[i][who[i][all]];
        }
        for (int i = 1; i <= sz; i++) {
          for (auto v : r[i][which[i]]) ans[v] = 2;
          for (auto v : r[i][which[i] ^ 1]) {
            if (n1) ans[v] = 1, n1--;
            else ans[v] = 3, n3--;
          }
        }
        cout << "YES" << '
    ';
        for (int i = 1; i <= n; i++) cout << ans[i];
      }
      return 0;
    }
    
  • 相关阅读:
    6. svg学习笔记-路径
    5. svg学习笔记-坐标系变换
    4. svg学习笔记-文档结构元素和样式的使用
    2. svg学习笔记-svg中的坐标系统和viewbox
    3. svg学习笔记-基本形状和画笔属性
    多项式:从门都没入到刚迈过门槛
    排列组合与二项式基础
    单调队列入门
    多项式:从什么都不知道到门都没入
    动态规划之四边形不等式优化
  • 原文地址:https://www.cnblogs.com/ChaseNo1/p/12918796.html
Copyright © 2011-2022 走看看