POJ 1419 Graph Coloring

大意不再赘述。

思路:在这一题中,题目给定的图一定是二分图,所以我们可以用到一种基于贪心思想的染色算法--顺序染色法,有的图是不能用顺序染色法来求解的。这种算法是一种近似的有效算法。由于每次从u最小的邻接顶点开始染色,所以输出的数字一定是严格的上升序。

顺序染色:

(1)用i表示顶点序号,i=1;

(2)用c表示给顶点i着色为第c中颜色,c=1;

(3)对第i个顶点着色:考虑它的每个邻接顶点,如果都没有使用第c中颜色 ,则给顶点i着色为第c种颜色,并转向第(5)步;否则,转向第(4)步。

(4)c = c+1,并转向第(3)步。

(5)若还有其他的顶点未着色,则i = i+1,并转向第(2)步,否则算法结束。

注意,这只是一种近似的有效算法。例如,二分图中i就可以用顺序染色,而有的图用这种算法求出来的结果是错误的。

这一题,我用回溯实现的。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdlib>
using namespace std;

const int MAXN = 110;

int G[MAXN][MAXN];
bool vis[MAXN], color[MAXN];

int n, m;
int MAX;

inline void init()
{
	memset(G, 0, sizeof(G));
	memset(vis, 0, sizeof(vis));
	memset(color, 0, sizeof(color));
}

inline int check(int u)
{
	for(int v = 1; v <= n; v++) if(G[u][v])
	{
		if(color[v]) return 0;
	}
	return 1;
}

void dfs(int u, int sum)
{
	if(u > n) //第(5)步
	{
		if(MAX < sum)
		{
			MAX = sum;
			memcpy(vis, color, sizeof(color));
		}
		return ;
	}
	if(n-u+1+sum <= MAX) return ; //剪枝 
	if(check(u)) //第(3)步 
	{
		color[u] = 1;
		dfs(u+1, sum+1);
		color[u] = 0;
	}
	dfs(u+1, sum);//第4步 
}

void read_case()
{
	init();
	scanf("%d%d", &n, &m);
	while(m--)
	{
		int u, v;
		scanf("%d%d", &u, &v);
		G[u][v] = G[v][u] = 1;
	}
}

void solve()
{
	int first = 1;
	read_case();
	MAX = -1;
	dfs(1, 0);
	printf("%d\n", MAX);
	for(int i = 1; i <= n; i++) if(vis[i])
	{
		if(first)
		{
			printf("%d", i);
			first = 0;
		}
		else
		{
			printf(" %d", i);
		}
	}
	printf("\n");
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		solve();
	}
	return 0;
}


你可能感兴趣的:(POJ 1419 Graph Coloring)