[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;
}

  

posted @ 2015-02-27 22:58  JoeFan  阅读(418)  评论(0编辑  收藏  举报