[BZOJ 1006] [HNOI2008] 神奇的国度 【弦图最小染色】
题目链接: BZOJ - 1006
题目分析
这道题是一个弦图最小染色数的裸的模型。
弦图的最小染色求法,先求出弦图的完美消除序列(MCS算法),再按照完美消除序列,从后向前倒着,给每个点染能染的最小颜色。
求出的颜色数就是最小染色,同时也是最大团。
代码
#include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int MaxN = 10000 + 5, MaxM = 1000000 + 5; int n, m, Ans; int V[MaxN], A[MaxN], Col[MaxN], Used[MaxN]; bool Visit[MaxN]; struct Edge { int v; Edge *Next; } E[MaxM * 2], *P = E, *Point[MaxN]; inline void AddEdge(int x, int y) { ++P; P -> v = y; P -> Next = Point[x]; Point[x] = P; } struct ES { int p, q; ES() {} ES(int a, int b) { p = a; q = b; } }; struct Cmp { bool operator () (ES e1, ES e2) { return e1.q < e2.q; } }; priority_queue<ES, vector<ES>, Cmp> Q; //MCS 求完美消除序列 void MCS() { for (int i = 1; i <= n; ++i) { V[i] = 0; Visit[i] = false; } while (!Q.empty()) Q.pop(); Q.push(ES(1, 0)); int x, y; for (int i = n; i >= 1; --i) { while (true) { x = Q.top().p; Q.pop(); if (!Visit[x]) break; } A[i] = x; Visit[x] = true; for (Edge *j = Point[x]; j; j = j -> Next) { y = j -> v; if (Visit[y]) continue; ++V[y]; Q.push(ES(y, V[y])); } } } void Min_Paint() { Ans = 1; int x; memset(Col, 0, sizeof(Col)); memset(Used, 0, sizeof(Used)); for (int i = n; i >= 1; --i) { for (Edge *j = Point[A[i]]; j; j = j -> Next) Used[Col[j -> v]] = i; x = 1; while (Used[x] == i) { ++x; if (x > Ans) Ans = x; } Col[A[i]] = x; } } int main() { scanf("%d%d", &n, &m); int a, b; for (int i = 1; i <= m; ++i) { scanf("%d%d", &a, &b); AddEdge(a, b); AddEdge(b, a); } MCS(); Min_Paint(); printf("%d\n", Ans); return 0; }