大意不再赘述。
思路:在这一题中,题目给定的图一定是二分图,所以我们可以用到一种基于贪心思想的染色算法--顺序染色法,有的图是不能用顺序染色法来求解的。这种算法是一种近似的有效算法。由于每次从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;
}