标签:
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