题意:给定一张图,现在对这张图进行染色,且相邻的两个点的颜色不能够相同,问最少要用多少种颜色?
思路:有一下贪心思路,对于没一个节点,我们对其周围的结点进行遍历,对有颜色的邻节点的颜色进行统计,选取一种编号最靠前且不与周边颜色冲突的颜色对改点进行涂色。由
于我们的涂色都是按编号从小到大因此该策略下能够产生最小的颜色集合。可以简单的证明下:假设现有N个点,对部分点已经进行了涂色,且满足条件,现在问题就是我们
的算法在要添加一种新颜色的时候还在用以前的颜色,导致后面出现了更多的颜色开销(违背贪心规则,如果确实这样的话,此题则变为动态规划求解),但是我们得出的推
论是,如果一个点应该被涂上新的颜色的话,那么我们可以通过在改点涂上一个已有的颜色,再将其相邻的结点涂上一种新颜色(同样也是增加了一种颜色)来达到同样的效
果。因此我们的算法是正确的。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <iostream> using namespace std; int N, G[30][30], color[30], ret[30]; void dfs(int x) { int c[30] = {0}; for (int i = 0; i < N; ++i) { if (G[x][i]) { c[color[i]] = 1; // 如果孩子没有染色的话就直接选定 } } for (int i = 1; i <= N; ++i) { if (!c[i]) { color[x] = i; if (!ret[i]) { ret[i] = 1; } break; } } for (int i = 0; i < N; ++i) { if (!color[i]) { dfs(i); } } return; } int main() { char rela[30]; int len; while (scanf("%d", &N), N != 0) { memset(G, 0, sizeof (G)); memset(color, 0, sizeof (color)); memset(ret, 0, sizeof (ret)); for (int i = 0; i < N; ++i) { scanf("%s", rela); len = strlen(rela); for (int j = 2; j < len; ++j) { G[i][rela[j]-'A'] = 1; } // 标号为0 - N-1 } dfs(0); int cnt = 0; for (int i = 1; i <= N; ++i) { if (ret[i]) { ++cnt; } } printf("%d", cnt); if (cnt == 1) { printf(" channel needed.\n"); } else { printf(" channels needed.\n"); } } return 0; }