http://poj.org/problem?id=1112
Time Limit: 1000MS | Memory Limit: 10000K | |||
Total Submissions: 6368 | Accepted: 1706 | Special Judge |
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
让组内的人都要相互认识,其实就是一个团。所以用求团的思路建图,如果两个人不互相认识,就建一条边。显然如果建出来的图不是二分图,那么一定无解。仔细分析,对于二分图的每一个联通块的人,在二分图不同边的一定不能放在一个组。所以我们求出每一个联通块在二分图不同边的数的数目,用x和y表示。那么对应每一个联通块都有对应的x和y值。那么我们可以用dp求出两个组的人数最接近为多少。在dp的过程中记录路径就可以输出方案。代码如下:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<vector> #define nn 110 #define inff 0x3fffffff typedef long long LL; using namespace std; int n; bool tu[nn][nn]; int vis[nn]; bool dp[nn][nn][nn]; int pre[nn][nn][nn]; struct node { int en,next; }E[2*nn*nn]; int p[nn],num,cnt; bool ok; vector<int>ve[nn][2]; vector<int>ans[2]; void init() { ans[0].clear(); ans[1].clear(); memset(p,-1,sizeof(p)); memset(pre,-1,sizeof(p)); memset(dp,false,sizeof(dp)); num=0; cnt=0; ok=true; memset(vis,-1,sizeof(vis)); for(int i=0;i<=n;i++) { ve[i][0].clear(); ve[i][1].clear(); } } void add(int st,int en) { E[num].en=en; E[num].next=p[st]; p[st]=num++; E[num].en=st; E[num].next=p[en]; p[en]=num++; } void dfs(int id,int co) { if(!ok) return ; vis[id]=co; ve[cnt][co].push_back(id); int i,w; for(i=p[id];i+1;i=E[i].next) { w=E[i].en; if(vis[w]==-1) dfs(w,1-co); else if(vis[w]==co) { ok=false; } if(!ok) return ; } } int main() { int i,x,j,g; while(scanf("%d",&n)!=EOF) { memset(tu,false,sizeof(tu)); for(i=1;i<=n;i++) { scanf("%d",&x); while(x) { tu[i][x]=true; scanf("%d",&x); } } init(); for(i=1;i<=n;i++) { for(j=i+1;j<=n;j++) { if(!tu[i][j]||!tu[j][i]) { add(i,j); } } } for(i=1;i<=n;i++) { if(vis[i]==-1) { cnt++; dfs(i,0); if(!ok) break; } } if(!ok) { puts("No solution"); continue; } dp[0][0][0]=true; int i1,i2; for(i=1;i<=cnt;i++) { i1=ve[i][0].size(); i2=ve[i][1].size(); for(j=0;j<=n;j++) { for(g=0;g+j<=n;g++) { if(j-i1>=0&&g-i2>=0) { if(dp[i-1][j-i1][g-i2]) { dp[i][j][g]=true; pre[i][j][g]=0; continue; } } if(j-i2>=0&&g-i1>=0) { if(dp[i-1][j-i2][g-i1]) { dp[i][j][g]=true; pre[i][j][g]=1; } } } } } for(i=n/2;i>=0;i--) { if(dp[cnt][i][n-i]) { break; } } i1=i,i2=n-i; while(cnt) { if(pre[cnt][i1][i2]==0) { i1-=ve[cnt][0].size(); i2-=ve[cnt][1].size(); for(i=0;i<(int)ve[cnt][0].size();i++) { ans[0].push_back(ve[cnt][0][i]); } for(i=0;i<(int)ve[cnt][1].size();i++) { ans[1].push_back(ve[cnt][1][i]); } cnt--; } else { i1-=ve[cnt][1].size(); i2-=ve[cnt][0].size(); for(i=0;i<(int)ve[cnt][1].size();i++) { ans[0].push_back(ve[cnt][1][i]); } for(i=0;i<(int)ve[cnt][0].size();i++) { ans[1].push_back(ve[cnt][0][i]); } cnt--; } } printf("%d",(int)ans[0].size()); for(i=0;i<(int)ans[0].size();i++) { printf(" %d",ans[0][i]); } puts(""); printf("%d",(int)ans[1].size()); for(i=0;i<(int)ans[1].size();i++) { printf(" %d",ans[1][i]); } puts(""); } return 0; }