码迷,mamicode.com
首页 > 其他好文 > 详细

UVa 1627 - Team them up!——[0-1背包]

时间:2016-06-01 00:01:17      阅读:613      评论:0      收藏:0      [点我收藏+]

标签:

Your task is to divide a number of persons into two teams, in such a way, that:

  • everyone belongs to one of the teams;
  • every team has at least one member;
  • every person in the team knows every other person in his team;
  • teams are as close in their sizes as possible.

This task may have many solutions. You are to find and output any solution, or to report that the solution does not exist.

Input 

The input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs.

 

 

For simplicity, all persons are assigned a unique integer identifier from 1 to N.

The first line in the input file contains a single integer number N (2 ≤ N ≤ 100) - the total number of persons to divide into teams, followed by N lines - one line per person in ascending order of their identifiers. Each line contains the list of distinct numbers Aij (1 ≤ Aij ≤ N, Aij ≠ i) separated by spaces. The list represents identifiers of persons that ith person knows. The list is terminated by 0.

Output 

For each test case, the output must follow the description below. The outputs of two consecutive cases will be separated by a blank line.

 

 

If the solution to the problem does not exist, then write a single message "No solution" (without quotes) to the output file. Otherwise write a solution on two lines. On the first line of the output file write the number of persons in the first team, followed by the identifiers of persons in the first team, placing one space before each identifier. On the second line describe the second team in the same way. You may write teams and identifiers of persons in a team in any order.

Sample Input 

2

5
3 4 5 0
1 3 5 0
2 1 4 5 0
2 3 5 0
1 2 3 4 0

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 

No solution

3 1 3 5
2 2 4


题意分析:
  以“不相互认识关系”建无向图,每个连通块都可以分成两队,如果存在已经分成一队的两个人互相不认识,说明无解,表现在图中就是存在环,用bfs求连通块即可。
将每个连通块中必须分到不同队的两组人分别记录下来team0,team1,接下来对求出的各个连通块动态规划,两队人数之差 dt=team0-team1,则要选择将每个连通块适当分组使dt最接近0。
  以d(i,j)表示已经选择前i个连通块,且dt=j时的最优解。
  状态转移方程为 d(i,j)=min{d(i-1,j-dt[i])+dt[i],d(i-1,j+dt[i]-dt[i])},其中dt[i]是指第i个连通块的两队人数差。
  用b(i,j)记录当前状态应该分组的方式,0表示将连通块的team0部分分到0组,1则表示将team0部分分到1组。
代码如下:
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <vector>
  7 using namespace std;
  8 const int maxn=110;
  9 #define INF 100000000
 10 int know[maxn][maxn];
 11 int unknow[maxn][maxn];
 12 int team[maxn];
 13 int n;
 14 vector<int> block[maxn][2];
 15 int num;
 16 int d[maxn][2*maxn];
 17 int b[maxn][2*maxn];
 18 bool dfs(int i,int t,vector<int> *b){
 19     team[i]=t;
 20     b[t].push_back(i);
 21     bool ok=true;
 22     for(int j=1;j<=n;j++){
 23         if(unknow[i][j]){
 24             if(team[j]==-1) {
 25                 if(!dfs(j,!t,b)){
 26                     ok=false;
 27                     break;
 28                 }
 29             }
 30             else if(team[j]!=t) continue;
 31             else{
 32                 ok=false;
 33                 break;
 34             }
 35         }
 36     }
 37     return ok;
 38 }
 39 bool blocks(){
 40     for(int i=0;i<maxn;i++)
 41         for(int j=0;j<2;j++)
 42             block[i][j].clear();
 43     num=0;
 44     for(int i=1;i<=n;i++)
 45         if(team[i]==-1)
 46             if(!dfs(i,0,block[num++]))
 47                 return false;
 48     return true;
 49 }
 50 void dp(){
 51     memset(d, 0, sizeof d);
 52     memset(b,0,sizeof b);
 53     for(int i=0;i<=num;i++){
 54         for(int j=0;j<2*maxn;j++){
 55             if(i==0){
 56                 d[i][j]=INF;
 57                 if(j==maxn)
 58                 d[i][j]=0;
 59                 continue;
 60             }
 61             d[i][j]=INF;
 62             int deta=block[i-1][0].size()-block[i-1][1].size();
 63             if(j-deta>=0&&j-deta<2*maxn&&d[i-1][j-deta]!=INF){
 64                 if(abs(d[i][j])>abs(d[i-1][j-deta]+deta)){
 65                     d[i][j]=d[i-1][j-deta]+deta;
 66                     b[i][j]=0;
 67                 }
 68             }
 69             if(j+deta>=0&&j+deta<2*maxn&&d[i-1][j+deta]!=INF){
 70                 if(abs(d[i][j])>abs(d[i-1][j+deta]-deta)){
 71                     d[i][j]=d[i-1][j+deta]-deta;
 72                     b[i][j]=1;
 73                 }
 74             }
 75             
 76         }
 77     }
 78 }
 79 void print(){
 80     int ans=INF,p=0;
 81     for(int k=0;k<2*maxn;k++){
 82         if(abs(ans)>abs(d[num][k])){
 83             ans=d[num][k];
 84             p=k;
 85         }
 86     }
 87     vector<int> team[2];
 88     for(int i=num,j=p;i>=0;i--){
 89         int dt=block[i-1][0].size()-block[i-1][1].size();
 90         int t=b[i][j];
 91         if(t==0){
 92             for(int k=0;k<block[i-1][0].size();k++)
 93                 team[0].push_back(block[i-1][0][k]);
 94             for(int k=0;k<block[i-1][1].size();k++)
 95                 team[1].push_back(block[i-1][1][k]);
 96             j-=dt;
 97         }
 98         else{
 99             for(int k=0;k<block[i-1][0].size();k++)
100                 team[1].push_back(block[i-1][0][k]);
101             for(int k=0;k<block[i-1][1].size();k++)
102                 team[0].push_back(block[i-1][1][k]);
103             j+=dt;
104         }
105     }
106     printf("%d",int(team[0].size()));
107     for(int i=0;i<team[0].size();i++){
108         printf(" %d",team[0][i]);
109     }
110     printf("\n");
111     printf("%d",int(team[1].size()));
112     for(int i=0;i<team[1].size();i++){
113         printf(" %d",team[1][i]);
114     }
115     printf("\n");
116    }
117 int main(int argc, const char * argv[]) {
118     int tt;
119     scanf("%d",&tt);
120     int cas=0;
121     while(tt--){
122         memset(know,0,sizeof know);
123         memset(unknow,0,sizeof know);
124         memset(team,-1,sizeof team);
125         
126         scanf("%d",&n);
127         for(int i=1;i<=n;i++){
128             int j;
129             while(scanf("%d",&j)&&j){
130                 know[i][j]=1;
131             }
132         }
133         
134         for(int j=1;j<=n;j++){
135             for(int i=1;i<=n;i++){
136                 if(i==j)
137                     continue;
138                 if(!know[i][j]){
139                     unknow[i][j]=unknow[j][i]=1;
140                 }
141             }
142         }
143         
144         if(!blocks()){
145             printf("No solution\n");
146             if(tt) printf("\n");
147             continue;
148         }
149         dp();
150         print();
151         if(tt) printf("\n");
152     }
153     
154     return 0;
155 }

 

UVa 1627 - Team them up!——[0-1背包]

标签:

原文地址:http://www.cnblogs.com/Kiraa/p/5547870.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!