链接:http://poj.org/problem?id=1112
题意是把一些人分成两组,要求每一组的人必须互相认识,并且两组的人数尽量的接近,如果我们用认识的关系进行建图,那么这道题将会相当麻烦,如果用不认识的关系建图,那么不认识人的两个人之间连一条边,可以把这些点分为一个二部图,然后对二部图进行染色标记,如果有不认识的两个人分在了同一组,那么就是无解的情况,否则,利用DP求解一个离n/2最近的值,并且记录路径
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define N 105 5 #define bug printf("hello\n"); 6 using namespace std; 7 int Abs(int a) 8 { 9 return a<0?-a:a; 10 } 11 int vis[N],p[N],s[N]; 12 bool map[N][N]; 13 int head[N],num; 14 int n; 15 struct node 16 { 17 int v,next; 18 }; 19 node e[N*N]; 20 int dp[N][N]; 21 int ans[N*3]; 22 int mark[N][N]; 23 void add(int u,int v) 24 { 25 e[num].v=v,e[num].next=head[u],head[u]=num++; 26 } 27 void init() 28 { 29 memset(head,-1,sizeof(head)); 30 memset(vis,0,sizeof(vis)); 31 memset(dp,0,sizeof(dp)); 32 memset(mark,0,sizeof(mark)); 33 memset(map,0,sizeof(map)); 34 memset(ans,0,sizeof(ans)); 35 num=0; 36 } 37 int dfs(int u,int kind,int f) 38 { 39 int i,v; 40 vis[u]=2*kind+f; 41 if(f==-1) 42 p[kind]++; 43 else 44 s[kind]++; 45 for(i=head[u];i>=0;i=e[i].next) 46 { 47 v=e[i].v; 48 if(vis[u]==vis[v]) 49 return 1; 50 if(vis[v]==0) 51 if(dfs(v,kind,-1-f)) return 1; 52 } 53 return 0; 54 } 55 void solve() 56 { 57 int i,j,u,v,k,so; 58 k=0; 59 for(i=1;i<=n;i++) 60 { 61 if(vis[i]==0) 62 { 63 k++; 64 if(dfs(i,k,-1)) 65 break; 66 } 67 } 68 if(i<=n) 69 printf("No solution\n"); 70 else 71 { 72 dp[0][0]=1; 73 for(i=0;i<k;i++) 74 for(j=0;j<=n;j++) 75 { 76 if(dp[i][j]) 77 { 78 dp[i+1][j+p[i+1]]=1; 79 dp[i+1][j+s[i+1]]=1; 80 mark[i+1][j+p[i+1]]=0; 81 mark[i+1][j+s[i+1]]=1; 82 } 83 } 84 j=n; 85 for(i=1;i<=n;i++) 86 { 87 if(dp[k][i]) 88 { 89 if(Abs(i-n+i)<j)//本应该是i-n/2这里扩大二倍 90 { 91 j=Abs(i-n+i); 92 so=i; 93 } 94 } 95 } 96 for(i=k;i>=1;i--)//寻找路径 97 { 98 if(mark[i][so]==0) 99 { 100 ans[2*i-1]=1; 101 so-=p[i]; 102 } 103 else 104 { 105 ans[2*i]=1; 106 so-=s[i]; 107 } 108 } 109 j=0; 110 for(i=1;i<=n;i++) 111 if(ans[vis[i]]) 112 j++; 113 printf("%d ",j); 114 for(i=1;i<=n;i++) 115 if(ans[vis[i]]) 116 printf("%d ",i); 117 printf("\n"); 118 printf("%d ",n-j); 119 for(i=1;i<=n;i++) 120 if(!ans[vis[i]]) 121 printf("%d ",i); 122 printf("\n"); 123 } 124 } 125 int main() 126 { 127 init(); 128 int i,j,u,v; 129 scanf("%d",&n); 130 for(i=1;i<=n;i++) 131 { 132 while(scanf("%d",&v)&&v) 133 map[i][v]=true; 134 } 135 for(i=1;i<=n;i++) 136 for(j=1;j<=n;j++) 137 { 138 if(i!=j&&!(map[i][j]&&map[j][i])) 139 add(i,j); 140 } 141 solve(); 142 return 0; 143 }