bzoj1006: [HNOI2008]神奇的国度
弦图最小染色。MCS(最大势)算法。定理为最小染色数 等于 最大团(最大完全子图(任意俩个节点都有一条边相连))。
1.必须是弦图。 弦图:对于任意长度大于3的环都存在弦的图。 弦:连接环上俩个不相邻节点的边。
反例:比方说5边形,它的最大团的节点数为2,但需要3种颜色才能染。
2.贪心,每回选已经被染色的邻接点数目最多的节点(编号最小)染色。
反例: 1——4——3——2,染完1以后应该染4,如果染2的话,计算出的最小染色数就会为3。其实应该是2。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #define val first #define id second using namespace std; const int maxn = 10000 + 10; const int maxm = 2000000 + 10; typedef pair<int,int> Node; priority_queue<Node> q; int n,m,c = -1; int h[maxn],to[maxm],next[maxm]; int seq[maxn],lable[maxn],c1[maxn]; bool vis[maxn],used[maxn]; void add(int u,int v) { to[++c] = v; next[c] = h[u]; h[u] = c; to[++c] = u; next[c] = h[v]; h[v] = c; } void build() { memset(h,-1,sizeof(h)); scanf("%d%d",&n,&m); for(int i = 1,a,b; i <= m; i++) { scanf("%d%d",&a,&b); add(a,b); } } void MCS() { for(int i = 1; i <= n; i++) q.push(Node(0,i)); for(int i = n,u; i >= 1; i--) { while(vis[q.top().id]) q.pop(); u = q.top().id; q.pop(); seq[i] = u; vis[u] = 1; for(int i = h[u]; ~i; i = next[i]) if(!vis[to[i]]) q.push(Node(++lable[to[i]],to[i])); } } int color() { int res = 0; for(int i = n; i >= 1; i--) { memset(used,0,sizeof(used)); for(int j = h[seq[i]]; ~j; j = next[j]) used[c1[to[j]]] = 1; for(c1[seq[i]] = 1; used[c1[seq[i]]]; c1[seq[i]]++); res = max(res,c1[seq[i]]); //printf("c1[%d] = %d\n",seq[i],c1[seq[i]]); } return res; } void solve() { MCS(); printf("%d\n",color()); } int main() { build(); solve(); return 0; }