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]); } }