一、题意

给出一个n个点m条边的连通图,每个点的度数不超过k(k为一个奇数),要求给每个点进行1...k的染色,使得相邻点颜色不同。

二、解析

首先按照题目的意思求出k,并且题目已经告诉我们k染色一定有解,因此接下来就是放心的dfs染色即可。
需要维护一个col[maxn]数组,0表示没有染色。这个col数组除了存放每个点的颜色,还充当了vis的角色。dfs的出口就是检查是否和周围已经染色的点重色了,没有则进行递归染色即可。

三、代码

#include <iostream>
#include <vector>
using namespace std;
const int maxn = 10000 + 5;
int n, m, k, col[maxn];
vector<int> G[maxn];

bool dfs(int u, int c) {
    col[u] = c;
    for(int v : G[u]) if(col[v] == c) {
        col[u] = 0;
        return 0;
    }
    // 由于可以保证一定有解,所以后面直接找解即可;否则还应该进行return 0的判断。
    for(int v : G[u]) if(!col[v]) {
        for(int i = 1; i <= k; i ++) if(dfs(v, i)) break;
    }
    return 1;
}

int main() {
    bool first = 1;
    while(cin >> n >> m) {
        k = 0;
        fill(col, col + n + 1, 0);
        for(int i = 1; i <= n; i ++) G[i].clear();

        while(m --) {
            int u, v;
            cin >> u >> v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        for(int i = 1; i <= n; i ++) k = max(k, (int)G[i].size());
        if(k % 2 == 0) k ++;
        dfs(1, 1);

        if(first) first = 0;
        else cout << endl;
        cout << k << endl;
        for(int i = 1; i <= n; i ++) cout << col[i] << endl;
    }
}

四、归纳

  • 染色问题 通过dfs解决,模板大致为:

    bool dfs(int u, int c) {
      col[u] = c;
      // 根据 [已染色的结点] 进行重色判断, 重色则失败
      for(int v : G[u]) if(col[v] == c) {
          col[u] = 0;
          return 0;
      }
    
      // 尝试对 [没染色的结点] 进行染色,同时也要进行是否成功的判断
      bool res = 1;
      for(int v : G[u]) if(!col[v]) {
          bool ok = 0;
          for(int i = 1; !ok && i <= k; i ++) if(dfs(v, i)) ok = 1;
          if(!ok) {   // 若某个点所有染色都染不了,则该次染色失败
              res = 0;
              break;
          }
      }
      return res;
    }