组队
【 问题描述】
你的任务是将一群人分到 两个队伍中,使得:
1、每个人都属于一个队伍。
2、每个队伍至少有一个人。
3、每个队伍的任意一个人都认识其他人。
4、两支队伍的人数尽可能接近。
这个任务可能有多组解,你可以输出 任意一种。
注意:认识是单向的且没有传递性。
【 输入格式 】
从文件 teams.in 中读入数据。
第一行为一个整数N,表示总人数。
接下来为N行,每行多个整数x,第i + 1 行描述编号为i的人认识x。每行以 0 结尾。
【 输出格式 】
输出到文件 teams.out 中。
如果无解输出−1;否则输出包含两行,每行的第一个数字表示该队伍的总人
数k,后面接着k个数字,表示被分到该队伍的人。
【 样例输入 】
5
2 3 5 0
1 4 5 3 0
1 2 5 0
1 2 3 0
4 3 2 1 0
【 样例输出 】
3 1 3 5
2 2 4
【 数据规模及约 定 】
对于分值为 30%的数据 , N <= 15
对于剩余分值为 70%的数据 , N <= 100
首先考虑转化一下,正难则反
将不互相认识的人连边,这样分队就变成了二分图匹配的过程
是否有解直接黑白染色
接下来对于每一个联通块
分成黑白点两个部分,显然因为每一个人都要分队,所以所有黑点分一边,白点分一边
所以就变成了给两队分配黑白点,使差值最小
令f[j][k]表示A队有j个人,B队有k个人,如果该状态存在,则转移
接下来枚举联通块i,黑点数s1,白点数s2
(1)f[j+s1][k+s2]=1
(2)f[j+s2][k+s1]=1
记录转移的路径from[j][k]表示j,k状态由什么联通块转移来
如果是第一种转移,那么from[j+s1][k+s2]=i
否则,from[j+s2][k+s1]=i+cnt(联通块数量)
之所以做区分是为了方便输出解
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 using namespace std; 7 struct Node 8 { 9 int next,to; 10 } edge[500001]; 11 int head[501],num,cnt,from[501][501],n,map[501][501],flag,f[501][501]; 12 vector<int>g[2][501],a1,a2; 13 int vis[501]; 14 void add(int u,int v) 15 { 16 num++; 17 edge[num].next=head[u]; 18 head[u]=num; 19 edge[num].to=v; 20 } 21 bool dfs(int x,int now) 22 { 23 int i; 24 vis[x]=now; 25 for (i=head[x]; i; i=edge[i].next) 26 { 27 int v=edge[i].to; 28 if (vis[v]==-1) 29 {if (!dfs(v,now^1)) return 0;} 30 else if (now==vis[v]) return 0; 31 } 32 return 1; 33 } 34 void insert(int x,int now) 35 { 36 int i; 37 vis[x]=now; 38 g[now][cnt].push_back(x); 39 for (i=head[x]; i; i=edge[i].next) 40 { 41 int v=edge[i].to; 42 if (vis[v]<0) 43 insert(v,now^1); 44 } 45 } 46 void solve(int x,int y) 47 { 48 int i; 49 while (x||y) 50 { 51 if (from[x][y]<=cnt) 52 { 53 int k=from[x][y]; 54 for (i=0; i<g[0][k].size(); i++) a1.push_back(g[0][k][i]); 55 for (i=0; i<g[1][k].size(); i++) a2.push_back(g[1][k][i]); 56 x-=g[0][k].size(); 57 y-=g[1][k].size(); 58 } 59 else 60 { 61 int k=from[x][y]-cnt; 62 for (i=0; i<g[1][k].size(); i++) a1.push_back(g[1][k][i]); 63 for (i=0; i<g[0][k].size(); i++) a2.push_back(g[0][k][i]); 64 x-=g[1][k].size(); 65 y-=g[0][k].size(); 66 } 67 } 68 cout<<a1.size()<<' '; 69 for (i=0; i<a1.size(); i++) 70 printf("%d ",a1[i]); 71 cout<<endl; 72 cout<<a2.size()<<' '; 73 for (i=0; i<a2.size(); i++) 74 printf("%d ",a2[i]); 75 cout<<endl; 76 } 77 int main() 78 { 79 int i,x,j,k; 80 cin>>n; 81 for (i=1; i<=n; i++) 82 { 83 scanf("%d",&x); 84 while (x) 85 { 86 map[i][x]=1; 87 scanf("%d",&x); 88 } 89 } 90 for (i=1; i<=n; i++) 91 for (j=1; j<=n; j++) 92 if (i!=j) 93 if (map[i][j]==0||map[j][i]==0) add(i,j); 94 memset(vis,-1,sizeof(vis)); 95 flag=1; 96 for (i=1; i<=n; i++) 97 if (vis[i]==-1) 98 { 99 if (!dfs(i,0)) 100 { 101 flag=0; 102 break; 103 } 104 } 105 if (flag==0) 106 { 107 cout<<-1; 108 return 0; 109 } 110 memset(vis,-1,sizeof(vis)); 111 for (i=1; i<=n; i++) 112 if (vis[i]==-1) 113 { 114 ++cnt; 115 insert(i,0); 116 } 117 f[0][0]=1; 118 for (i=1; i<=cnt; i++) 119 { 120 for (j=n; j>=0; j--) 121 for (k=n; k>=0; k--) 122 if (f[j][k]) 123 { 124 int s1=g[0][i].size(),s2=g[1][i].size(); 125 if (f[j+s1][k+s2]==0) 126 { 127 f[j+s1][k+s2]=1; 128 from[j+s1][k+s2]=i; 129 } 130 if (f[j+s2][k+s1]==0) 131 { 132 f[j+s2][k+s1]=1; 133 from[j+s2][k+s1]=i+cnt; 134 } 135 } 136 } 137 for (i=0; i<=n; i++) 138 { 139 for (j=1; j<=n; j++) 140 if (j+j+i==n) 141 if (f[j][j+i]||f[j+i][j]) 142 { 143 if (f[j][j+i]) solve(j,j+i); 144 else solve(j+i,j); 145 return 0; 146 } 147 } 148 return 0; 149 }