关于图的m着色问题

以前一直以为图的着色问题解等于最大团的顶点数,今天发现原来是有问题的,例如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;
}


你可能感兴趣的:(关于图的m着色问题)