以前一直以为图的着色问题解等于最大团的顶点数,今天发现原来是有问题的,例如5个顶点的环最大团顶点数为2,但却需要三种颜色。关于m着色问题可以用二分+DLX解决,应该会比爆搜要快。
poj 1129
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> #include <bitset> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::stringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; using std::unique; using std::lower_bound; using std::random_shuffle; using std::bitset; using std::upper_bound; using std::multiset; typedef long long LL; typedef unsigned long long ULL; typedef unsigned UN; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; typedef LL TY; typedef long double LF; const int MAXN(710); const int MAXM(18010); const int MAXE(8000010); const int MAXK(6); const int HSIZE(13131); const int SIGMA_SIZE(26); const int MAXH(13); const int INFI((INT_MAX-1) >> 1); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); const int MOD(20100403); const double EPS(1e-7); const LF PI(acos(-1.0)); template<typename T> void checkmax(T &a, T b){if(b > a) a = b;} template<typename T> void checkmin(T &a, T b){if(b < a) a = b;} template<typename T> T ABS(const T &a){return a < 0? -a: a;} int N; struct DLX { int H[MAXN]; int S[MAXM]; int L[MAXE], U[MAXE], R[MAXE], D[MAXE], C[MAXE]; int size; void init(int n, int m) { for(int i = 0; i <= n; ++i) H[i] = -1; for(int i = 0; i <= m; ++i) { U[i] = D[i] = C[i] = i; S[i] = 0; L[i+1] = i; R[i] = i+1; } L[0] = m; R[m] = 0; size = m+1; } void link(int r, int c) { ++S[C[size] = c]; D[size] = D[c]; U[D[c]] = size; U[size] = c; D[c] = size; if(H[r] == -1) L[size] = R[size] = H[r] = size; else { R[size] = R[H[r]]; L[R[H[r]]] = size; L[size] = H[r]; R[H[r]] = size; } ++size; } void remove(int c) { L[R[c]] = L[c]; R[L[c]] = R[c]; for(int i = D[c]; i != c; i = D[i]) for(int j = R[i]; j != i; j = R[j]) { --S[C[j]]; U[D[j]] = U[j]; D[U[j]] = D[j]; } } void resume(int c) { L[R[c]] = R[L[c]] = c; for(int i = U[c]; i != c; i = U[i]) for(int j = L[i]; j != i; j = L[j]) { ++S[C[j]]; U[D[j]] = D[U[j]] = j; } } bool dfs(int dep) { int c, sz = INFI; for(int i = R[0]; i && i <= N; i = R[i]) if(S[i] < sz) { c = i; sz = S[i]; } if(sz == INFI) return true; remove(c); for(int i = D[c]; i != c; i = D[i]) { for(int j = R[i]; j != i; j = R[j]) remove(C[j]); if(dfs(dep+1)) return true; for(int j = L[i]; j != i; j = L[j]) resume(C[j]); } resume(c); return false; } } dlx; vector<int> g[26]; char str[50]; //行决策为每个点选什么颜色,前N列表示选择第i个点,后面的val*N*N表示第i个节点选择颜色j与点k冲突 bool check(int val) { dlx.init(val*N, N+val*N*N); for(int i = 0; i < N; ++i) { for(int j = 0; j < val; ++j) { int tr = i*val+j+1; dlx.link(tr, i+1); for(vector<int>::iterator it = g[i].begin(); it != g[i].end(); ++it) //点k { dlx.link(tr, N+i*val*N+*it*val+j+1); dlx.link(tr, N+*it*val*N+i*val+j+1); } } } return dlx.dfs(0); } int main() { while(scanf("%d", &N), N) { for(int i = 0; i < N; ++i) g[i].clear(); for(int i = 0; i < N; ++i) { scanf("%s", str); int u = str[0]-'A'; for(int j = 2; str[j]; ++j) { int v = str[j]-'A'; g[u].push_back(v); } } int l = 1, r = N; while(l < r) { int m = (l+r) >> 1; if(check(m)) r = m; else l = m+1; } printf("%d channel%s needed.\n", l, l == 1? "":"s"); } return 0; }