这道题目我一点思路都没有,不会做呀。。。。
看了http://www.cppblog.com/linyangfei/archive/2008/08/08/58295.html
http://happylch21.blog.163.com/blog/static/165639759201162911032307/
这两位大牛的,把他们两的结合起来~~
题目的大意就是:
把n个人分成2各组,每一个人有他所认识的人。所分的组有四点要求:
1、 每个人都必需属于一个组。
2、 每个组至少有一个人。
3、 每个组里面的每个人必需互相认识。
4、 两个组的成员应尽量接近。
思路:建立图,若i关注了j,j也关注了i则i与j建立一条双向边~,然后求这个图的补图,那么补图中的边连的两个点必然不能在一个组中是两个互斥的点,这样分成两个组,这样就转化成2分染色问题,深度遍历进行染色,若染色过程中,发现同组有相邻点,则表示无解。求出每组中包含了多少个结点和每组包含了哪些结点
num[i][0]表示第i个强连通分量里颜色为0的个数,num[i][1]表示第i个强连通分量里颜色为1的个数。
p[i][0][k]表示第i个连通分量里颜色为0的第k个点是哪个结点,同理p[i][1][k]表示第i个连通分量里颜色为1的第k个点是哪个结点。
然后转换为0/1背包问题
dp[i][j]表示前i对数能否将容量j填满
dp[i][j] = dp[i][j - num[i][0]] ; j > num[i][0]
dp[i][j] = dp[i][j - num[i][1]]; j > num[i][1]
同时记录路径
dp[i][n/2]即为最终的结果
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 110;
bool graph[maxn][maxn], dp[maxn][maxn/2];
int n, cnt, p[maxn][2][maxn], num[maxn][2], color[maxn], path[maxn][maxn];
bool dfs(int u);
void compute();
int main()
{
scanf("%d", &n);
memset(graph, 0, sizeof(graph));
memset(num, 0, sizeof(num));
memset(color, -1, sizeof(color));
for(int i = 1; i <= n; i++)
{
while(true)
{
int index;
scanf("%d", &index);
if(index == 0)
break;
graph[i][index] = true;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = i + 1; j <= n; j++)
{
if(graph[i][j] && graph[j][i])
graph[i][j] = graph[j][i] = false;
else
graph[i][j] = graph[j][i] = true;
}
}
cnt = 0;
for(int i = 1; i <= n; i++)
{
if(color[i] == -1)
{
color[i] = 0;
if(!dfs(i))
{
printf("No solution\n");
return 0;
}
cnt++;
}
}
compute();
return 0;
}
bool dfs(int u)
{
int col = color[u];
int index = num[cnt][col];
num[cnt][col]++;
p[cnt][col][index] = u;
for(int i = 1; i <= n; i++)
{
if(graph[u][i])
{
if(color[i] == -1)
{
color[i] = col ^ 1;
if(!dfs(i))
return false;
}
else if(color[u] == color[i])
return false;
}
}
return true;
}
void compute()
{
int i, j, k, tmp, res, col;
memset(dp, 0, sizeof(dp));
dp[0][num[0][0]] = true;
path[0][num[0][0]] = 0;
dp[0][num[0][1]] = true;
path[0][num[0][1]] = 1;
for(i = 1; i < cnt; i++)
{
for(j = n / 2; j >= 0; j--)
{
dp[i & 1][j] = false;
tmp = j - num[i][0];
if(tmp >= 0 && dp[(i-1) & 1][tmp])
{
dp[i & 1][j] = true;
path[i][j] = 0;
if(i == cnt - 1)
break;
continue;
}
tmp = j - num[i][1];
if(tmp >= 0 && dp[(i-1) & 1][tmp])
{
dp[i & 1][j] = true;
path[i][j] = 1;
if(i == cnt - 1)
break;
}
}
}
tmp = j;
res = 0;
for(i = cnt - 1; i >= 0; i--)
{
if(path[i][j] == 0)
{
res += num[i][0];
j -= num[i][0];
}
else
{
res += num[i][1];
j -= num[i][1];
}
}
printf("%d", res);
j = tmp;
for(i = cnt - 1; i >= 0; i--)
{
col = 1;
if(path[i][j] == 0)
{
col = 0;
j -= num[i][0];
}
else
j -= num[i][1];
for(k = 0; k < num[i][col]; k++)
printf(" %d", p[i][col][k]);
}
printf("\n%d", n - res);
j = tmp;
for(i = cnt - 1; i >= 0; i--)
{
col = 0;
if(path[i][j] == 0)
{
col = 1;
j -= num[i][0];
}
else
j -= num[i][1];
for(k = 0; k < num[i][col]; k++)
printf(" %d", p[i][col][k]);
}
printf("\n");
}