POJ1112——Team Them Up!(动态规划,二分图判定)

来源:互联网 发布:淘宝客服服务流程 编辑:程序博客网 时间:2024/06/06 09:21

Team Them Up!
Time Limit: 1000MS
Memory Limit: 10000KTotal Submissions: 7454
Accepted: 2011
Special Judge

Description

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

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

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

52 3 5 01 4 5 3 01 2 5 01 2 3 04 3 2 1 0

Sample Output

3 1 3 52 2 4


题意:

你的任务是把一些人  分成两组, 需要满足以下条件: 
每个人都在一个队伍里
每个队至少一个人; 
每个在队里的人都认识队里的其他人; 
两个队伍相差的人数尽量少. 
可能有多种解,输出其中任何一种;或者输出无解

思路:首先得判断出谁和谁一定不能在一组,很自然地想到二分图染色。只有两个人相互认识才能在同一个队伍。所以针对不能在同一个队伍地人连边,然后二分图染色。

染色的过程中得统计不同颜色有多少人,哪些人。分成不同的连通块。

然后问题就转化成了,比如有m个连通块,x[i]和y[i]代表不同的颜色。对于每个连通块,需要在x和y中选一个,统计总人数,使得最后两组人数差最小。

我觉得我写得好像很复杂,但因为数据量很小所以也能过。

dp[i][j]表示一组i个人,一组j个人的状态能否达到。

ans[i][j][k]表示该状态可以达到的情况下,第k个连通块选了x还是y。

最后再算一下最小值,更新结果。

写得太浪了。。。


#include <stdio.h>#include <string.h>#include <vector>#include <queue>#include <algorithm>#include <cmath>using namespace std;#define MAXN 110#define INF 1000000007vector <int> G[MAXN];int V;int color[MAXN];vector <int> x[MAXN];vector <int> y[MAXN];int d[MAXN][MAXN];int dp[MAXN][MAXN];int ans[MAXN][MAXN][MAXN];int num=0;bool dfs(int v,int c){    color[v]=c;    if(c>0)        x[num].push_back(v);    else        y[num].push_back(v);    for(int i=0;i<G[v].size();i++){        if(color[G[v][i]]==c)            return false;        if(color[G[v][i]]==0&&!dfs(G[v][i],-c)){            return false;        }    }    return true;}int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=n;i++){        int t;        while(scanf("%d",&t)&&t){            d[i][t]=1;        }    }    for(int i=1;i<n;i++){        for(int j=i+1;j<=n;j++){            if(!d[i][j]||!d[j][i])            {                G[i].push_back(j);                G[j].push_back(i);            }        }    }    for(int i=1;i<=n;i++){        if(!color[i]){            if(dfs(i,1)){                num++;            }            else{                printf("No solution\n");                return 0;            }        }    }    memset(dp,0,sizeof(dp));    vector <int>r1;    vector <int> r2;    int m=n/2;    dp[0][0]=1;    memset(ans,-1,sizeof(ans));    for(int k=0;k<num;k++){        for(int i=0;i<=n;i++){            for(int j=0;j<=n;j++){                if(dp[i][j]&&ans[i][j][k]==-1){                    int a=x[k].size(),b=y[k].size();                    if(dp[i+a][j+b]==0){                        dp[i+a][j+b]=1;                        ans[i+a][j+b][k]=0;                        //printf("<<<%d %d %d >>>\n",i+a,j+b,ans[i+a][j+b][k]);                        for(int t=0;t<k;t++)                            ans[i+a][j+b][t]=ans[i][j][t];                    }                    if(dp[i+b][j+a]==0){                        dp[i+b][j+a]=1;                        ans[i+b][j+a][k]=1;                        //printf("<<<%d %d %d >>>\n",i+b,j+a,ans[i+b][j+a][k]);                        for(int t=0;t<k;t++)                            ans[i+b][j+a][t]=ans[i][j][t];                    }                }            }        }    }    int min_f=INF;    for(int i=1;i<=n/2;i++){        int j=n-i;        if(dp[i][j]){            if((j-i)<min_f){                r1.clear();                r2.clear();                for(int k=0;k<num;k++){                    if(ans[i][j][k]==0){                        for(int s=0;s<x[k].size();s++){                            r1.push_back(x[k][s]);                        }                        for(int s=0;s<y[k].size();s++){                            r2.push_back(y[k][s]);                        }                    }                    else{                        for(int s=0;s<y[k].size();s++){                            r1.push_back(y[k][s]);                        }                        for(int s=0;s<x[k].size();s++){                            r2.push_back(x[k][s]);                        }                    }                }            }        }    }    printf("%d ",r1.size());    for(int i=0;i<r1.size();i++)        printf(" %d",r1[i]);    printf("\n");    printf("%d ",r2.size());    for(int i=0;i<r2.size();i++)        printf(" %d",r2[i]);    printf("\n");}


0 0
原创粉丝点击