二着色+DP
在不是互相认识的节点之间连一条边,最后得到由多个连通分量构成的图。把图中节点分为两组,保证图中每条边的两个顶点不能再同一组。对每个连通分量进行二着色,每个连通分量的点就分为了a,b两组。假定最后整个图分为1,2两组。每个连通分量的a,b两组,无非一个在1组一个在2组,通过DP,确定每个连通分量中a,b哪个在1组,哪个在2组时最有。然后就是DP的过程,没想出来,看了其他人的结题报告。f[i][j]表示对于前i个联通分量,是否可达到第1组和第2组的差值为j的状态。设a为连通分量i的两组的差值则f[i][j]=1当f[i-1][j-a]==1||f[i-1][j+a]==1。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int maxn=100+10; 6 int g[maxn][maxn]; 7 int color[maxn]; 8 int mark[maxn][3][maxn]; 9 int amount[maxn][maxn*2]; 10 int co1[maxn][3]; 11 int n,tot; 12 int f[maxn][maxn*2],path[maxn][maxn*2]; 13 int dfs_color(int u) 14 { 15 int i; 16 for(i=1;i<=n;i++) 17 { 18 if(i!=u&&(!g[u][i]||!g[i][u])) 19 { 20 if(color[i]==color[u]) return 0; 21 if(!color[i]) 22 { 23 color[i]=3-color[u]; 24 mark[tot][color[i]][co1[tot][color[i]]++]=i; 25 if(!dfs_color(i)) return 0; 26 } 27 } 28 } 29 return 1; 30 } 31 void print(int ans) 32 { 33 printf("%d",amount[tot][ans]); 34 int i,j,loc,tem=ans; 35 for(i=tot;i>=1;i--) 36 { 37 loc=path[i][tem]; 38 for(j=0;j<co1[i][loc];j++) printf(" %d",mark[i][loc][j]); 39 tem=tem-(co1[i][loc]-co1[i][3-loc]); 40 } 41 tem=ans; 42 printf(" "); 43 printf("%d",n-amount[tot][ans]); 44 for(i=tot;i>=1;i--) 45 { 46 loc=3-path[i][tem]; 47 for(j=0;j<co1[i][loc];j++) printf(" %d",mark[i][loc][j]); 48 tem=tem-(co1[i][3-loc]-co1[i][loc]); 49 } 50 printf(" "); 51 } 52 int main() 53 { 54 scanf("%d",&n); 55 int i,tem,j,a; 56 for(i=1;i<=n;i++) 57 { 58 while(scanf("%d",&tem)&&tem) g[i][tem]=1; 59 } 60 int flag=0; 61 tot=0; 62 for(i=1;i<=n;i++) 63 { 64 if(!color[i]) 65 { 66 tot++; 67 color[i]=1; 68 mark[tot][1][co1[tot][1]++]=i; 69 if(!dfs_color(i)) 70 { 71 flag=1; 72 break; 73 } 74 } 75 } 76 if(flag) printf("No solution "); 77 else 78 { 79 int a1,a2; 80 f[1][co1[1][1]-co1[1][2]+n]=1; 81 f[1][co1[1][2]-co1[1][1]+n]=1; 82 path[1][co1[1][1]-co1[1][2]+n]=1; 83 path[1][co1[1][2]-co1[1][1]+n]=2; 84 amount[1][co1[1][1]-co1[1][2]+n]=co1[1][1]; 85 amount[1][co1[1][2]-co1[1][1]+n]=co1[1][2]; 86 for(i=2;i<=tot;i++) 87 { 88 a=co1[i][1]-co1[i][2]; 89 for(j=0;j<=2*n;j++) 90 { 91 if((j-a)>=0&&(j-a)<=2*n&&f[i-1][j-a]==1) 92 { 93 f[i][j]=1; 94 path[i][j]=1; 95 amount[i][j]=amount[i-1][j-a]+co1[i][1]; 96 } 97 else if((j+a)>=0&&(j+a)<=2*n&&f[i-1][j+a]==1) 98 { 99 f[i][j]=1; 100 path[i][j]=2; 101 amount[i][j]=amount[i-1][j+a]+co1[i][2]; 102 } 103 } 104 } 105 106 for(i=n;i<=2*n;i++) if(f[tot][i]) break; 107 for(j=n-1;j>=0;j--) if(f[tot][j]) break; 108 int ans=(i-n)<(n-j)?i:j; 109 print(ans); 110 } 111 return 0; 112 }