poj1419Graph Coloring

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 4379 Accepted: 1985 Special Judge

Description

You are to write a program that tries to find an optimal coloring for a given graph. Colors are applied to the nodes of the graph and the only available colors are black and white. The coloring of the graph is called optimal if a maximum of nodes is black. The coloring is restricted by the rule that no two connected nodes may be black.



Figure 1: An optimal graph with three black nodes

Input

The graph is given as a set of nodes denoted by numbers 1...n, n <= 100, and a set of undirected edges denoted by pairs of node numbers (n1, n2), n1 != n2. The input file contains m graphs. The number m is given on the first line. The first line of each graph contains n and k, the number of nodes and the number of edges, respectively. The following k lines contain the edges given by a pair of node numbers, which are separated by a space.

Output

The output should consists of 2m lines, two lines for each graph found in the input file. The first line of should contain the maximum number of nodes that can be colored black in the graph. The second line should contain one possible optimal coloring. It is given by the list of black nodes, separated by a blank.

Sample Input

1
6 8
1 2
1 3
2 4
2 5
3 4
3 6
4 6
5 6

Sample Output

3
1 4 5

Source

Southwestern European Regional Contest 1995

求最大独立集

独立集就是在一个图中选取一些点,这些点互不相邻,这个点集就是独立集

最大独立集就是点最多的独立集,很显然,一个图至少一个

最大独立集跟图的补图的最大团是一样的

图的补图就是把一个图原来的边都删掉,把原来互相之间没有边的点相连

最大团就是一个图的最大完全子图

完全子图就是一个图的子图是个完全图

最大完全子图就是完全子图上的点最多,很显然,一个图至少一个

求最大团就是NP完全,我学了一种爆搜

大概思路就是维护三个数组

a数组存放一个正在考虑的完全子图,b数组存放一个当前最大完全子图,

c数组存放第i个点到最后一个点这个区域内所能形成的最大团的点的数量,

很显然,c是用来剪枝的

从最后一个点依次往前选点作为第一个点丢到a中进行搜索,显然这种作法是为了维护c

由于a如果可以扩展,那么肯定是由与a中的点相邻的连点扩展(相邻就是直接与点连接),

考虑这些点,如果选出来的点跟a中所有点都相邻,那么这个点丢到a的尾巴,进行下一次搜索,

同样为了维护c,当从a中选择一个点作为前驱开始扩展时,我们枚举比这个点下标大的点里

是否有它的相邻点,如果有,就开始考虑这些点,若是当前a的数量加上c[i](i为这些点的下标),

还是无法更新当前最大团,那么就不用再考虑这个前驱了,停止关于这个前驱的扩展,

为了再快一点,每次搜索如果更新了当前最大团就停止这次搜索,换个起点我们再来,

为何这样可以保证正确性,因为毕竟我们枚举了所有起点,考虑到了所有情况,

如若不停止,反而会多出一些重复情况。

这种爆搜不太好的地方就是必须要用邻接矩阵,很浪费内存,速度的话看RP,过这个题是没问题的。
#include<map>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<climits>
#include<list>
#include<iomanip>
#include<stack>
#include<set>
using namespace std;
bool edge[110][110];
int n,ans,group[110],box[110],cnt[110];//box存放当前选取的点,group存放当前最大团,cnt存放第i位后可形成的最大团
bool dfs(int s,int num)
{
	for(int i=s+1;i<=n;i++)
	{
		if(cnt[i]+num<=ans)
			return 0;
		if(edge[s][i])
		{
			int j;
			for(j=0;j<num;j++)
				if(!edge[i][box[j]])
					break;
			if(j==num)
			{
				box[num]=i;
				if(dfs(i,num+1))
					return 1;
			}
		}
	}
	if(ans<num)
	{
		ans=num;
		memcpy(group,box,sizeof(int)*ans);
		return 1;
	}
	return 0;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int m;
		cin>>n>>m;
		memset(edge,0,sizeof(edge));
		while(m--)
		{
			int from,to;
			cin>>from>>to;
			edge[from][to]=edge[to][from]=1;
		}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if(i!=j)
					edge[i][j]^=1;
		ans=1;
		for(int i=n;i>0;i--)
		{
			box[0]=i;
			dfs(i,1);
			cnt[i]=ans;
		}
		cout<<ans<<endl;
		for(int i=0;i<ans;i++)
			printf(i==0?"%d":i==ans-1?" %d\n":" %d",group[i]);
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值