组队

【 问题描述】
你的任务是将一群人分到 两个队伍中,使得:
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 }

 

posted @ 2017-10-23 21:54  Z-Y-Y-S  阅读(283)  评论(0编辑  收藏  举报