标签:
Description
Input
Output
Sample Input
5 2 3 5 0 1 4 5 3 0 1 2 5 0 1 2 3 0 4 3 2 1 0
Sample Output
3 1 3 5 2 2 4
Source
给定 n 个人的认识关系有向图,将他们分为 2 组人,每组的人要相互认识,且两组人数相差尽量小。
构建新图,两个人不相互认识则连一条无向边。然后二分染色(同时记录每个联通块内有哪些点son[i][++num[i]],数量差dis[i]: 0 颜色 - 1 颜色),如果不是二分图,那么就无解。
dp[i][j]表示前i个联通块分两组后第1组-第2组=j的分法是否存在。
差值可能是负数,因此坐标平移,j=差值+100。
dp[i-1][j]==1 则 dp[i][j+dis[i]]=1,dp[i][j-dis[i]]=1;
同时记录新状态是否是由前一状态的差值-dis[i]转移来的:
path[i][j+dis[i]]=1,path[i][j-dis[i]=0;
dp[cnt][ d+100]==1中绝对值最小的 d 就是最小差值,然后从第cnt个联通块推回去,如果path[i][j]^color[当前联通块的点]==1说明这个点是第1组的,因为path[i][j]==1代表第i个联通块的0颜色给第一组。异或为1,则path为0,color为1或者path为1,color为0。
path[i][j]为1,则第 i-1 个联通块时的差值就是当前差值+dis[i]。否则-dis[i]。
#include <cstdio>
#define N 205
#define sf(a) scanf("%d",&a)
using namespace std;
int n,g[N][N],gg[N][N];//原图和新图
int color[N];//染色
int dis[N];//一个联通块里0色-1色的数量差
int cnt,son[N][N];//储存1~cnt联通块的节点
int num[N];//1~cnt联通块的个数
int dp[N][N],path[N][N];//dp和路径记录
int tot[2],team[2][N];//记录两个队的人数和队员
int cl[2];//0色和1色的数量
int dfs(int x,int c){//将x染上c色(0,1)
color[x]=c;
for(int i=1;i<=n;i++)if(gg[x][i]&&i!=x){
if(color[i]==c)return 0;
if(color[i]==-1&&!dfs(i,!c))return 0;
}
cl[c]++;
son[cnt][++num[cnt]]=x;
return 1;
}
int check(){
for(int i=1;i<=n;i++)if(color[i]==-1){
cnt++;
cl[1]=cl[0]=0;
if(!dfs(i,1))return 0;
dis[cnt]=cl[0]-cl[1];
}
return 1;
}
void solve(){
dp[0][100]=1;
for(int i=1;i<=cnt;i++)
for(int j=0;j<=200;j++)if(dp[i-1][j]){
dp[i][j+dis[i]]=1;
path[i][j+dis[i]]=1;
if(j>dis[i]){
dp[i][j-dis[i]]=1;
path[i][j-dis[i]]=0;
}
}
int d=0;
for(;d<100&&!(dp[cnt][d+100]||dp[cnt][-d+100]);d++);
if(dp[cnt][d+100])d+=100;else d=100-d;
for(int i=cnt;i;i--){
for(int j=1;j<=num[i];j++){
if(path[i][d]^color[j])team[1][++tot[1]]=son[i][j];
else team[0][++tot[0]]=son[i][j];
}
if(path[i][d]) d-=dis[i];
else d+=dis[i];
}
for(int j=0;j<2;j++)
{
printf("%d ",tot[j]);
for(int i=1;i<=tot[j];i++)
printf("%d ",team[j][i]);
puts("");
}
}
int main() {
sf(n);
for(int i=1;i<=n;i++){
int x;
while(sf(x),x)
g[i][x]=1;
color[i]=-1;
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(!g[i][j]||!g[j][i])
gg[i][j]=gg[j][i]=1;
if(check()) solve();
else puts("No solution");
}
【POJ 1112】Team Them Up!(二分图染色+DP)
标签:
原文地址:http://www.cnblogs.com/flipped/p/5781741.html