POJ 1112-Team Them Up!图论+DP

链接: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 }

 

posted @ 2012-08-25 11:24  zhenhai  阅读(210)  评论(0编辑  收藏  举报