哇。。终于给写出来了。。

题意很简单:

n个人分成2各组,每一个人有他所认识的人。所分的组有四点要求:

1、 每个人都必需属于一个组。

2、 每个组至少有一个人。

3、 每个组里面的每个人必需互相认识。

4、 两个组的成员应尽量接近。

刚开始的时候以为只有一个连通分量呢,没想那么多,一直wa,后来发现每个人都用dp,感觉很纳闷,最后想想才发现,有可能有很多个连通分量。。。

感觉用并查集处理起来会比较麻烦,就改用广搜了,然后记录每一个点层次

如果是第k个连通分量的,奇数层次上的点存在s1[k][]里面,s1[k][0]记录点的个数,偶数层次上的放在s2[k][]里面,s2[k][0]记录点的个数。。

判断一下s1[k]里面的任意两个点是否都能认识, s2[k]里面的任意两个点是否都能认识, 如果存在不认识的,就直接返回No solution

最后用背包背下就行了,dp初始化很重要,dp[0][0]=1,其他的全部赋为0,

代码:

View Code
  1 # include<stdio.h>
  2 # include<string.h>
  3 # include<queue>
  4 using namespace std;
  5 int map[105][105],dp[105][105],adj[105][105],visit[105],n,m,s1[105][105],s2[105][105],pre1[105];
  6 struct node{
  7     int xuhao,val;
  8 };
  9 void dfs(int i)/*纯广搜*/
 10 {
 11     int j,ans;
 12     queue<node>q;
 13     node cur,next;
 14     cur.xuhao=i;
 15     cur.val=1;/*顶点的层次赋为1*/
 16     q.push(cur);
 17     visit[i]=1;
 18     m++;
 19     while(!q.empty())
 20     {
 21         cur=q.front();
 22         q.pop();
 23         ans=cur.xuhao;
 24         if(cur.val%2==1) {s1[m][0]++;s1[m][s1[m][0]]=ans;}
 25         else {s2[m][0]++;s2[m][s2[m][0]]=ans;}
 26         for(j=1;j<=n;j++)
 27         {
 28             if(j!=ans && visit[j]==0 && adj[ans][j]==1)
 29             {
 30                 next.xuhao=j;
 31                 next.val=cur.val+1;
 32                 visit[j]=1;
 33                 q.push(next);
 34             }
 35         }
 36     }
 37 }
 38 int main()
 39 {
 40     int i,j,t,h,k,ncase,k1,flag,x;
 41     scanf("%d",&t);
 42     for(ncase=1;ncase<=t;ncase++)
 43     {
 44         if(ncase!=1) printf("\n");
 45         scanf("%d",&n);
 46         memset(map,0,sizeof(map));
 47         for(i=1;i<=n;i++)
 48         {
 49             while(scanf("%d",&x)!=EOF &&x)
 50                 map[i][x]=1;
 51         }
 52         memset(adj,0,sizeof(adj));
 53         for(i=1;i<=n;i++)
 54         {
 55             for(j=i+1;j<=n;j++)
 56                 if(map[i][j]==0 || map[j][i]==0) {adj[i][j]=1;adj[j][i]=1;}/*把不认识的连在起来*/
 57         }
 58         memset(visit,0,sizeof(visit));
 59         for(i=1;i<=n+1;i++)
 60         {
 61             s1[i][0]=0;
 62             s2[i][0]=0;
 63         }/*初始化每一个连通分量*/
 64             m=0;/*表示连通分量的个数*/
 65         flag=0;
 66         for(i=1;i<=n;i++)
 67         {
 68             if(visit[i]==0)/*如果该点没有被访问过*/
 69             {
 70                 dfs(i);
 71                 for(j=1;j<=s1[m][0];j++)
 72                 {
 73                     for(k=j+1;k<=s1[m][0];k++)
 74                         if(adj[s1[m][j]][s1[m][k]]==1) {flag=1;break;}
 75                         if(flag==1) break;
 76                 }
 77                 for(j=1;j<=s2[m][0];j++)
 78                 {
 79                     for(k=j+1;k<=s2[m][0];k++)
 80                         if(adj[s2[m][j]][s2[m][k]]==1) {flag=1;break;}
 81                 }/*判断一下每一个连通分量里面的点是否都能认识*/
 82             }
 83             if(flag==1) break;
 84         }
 85         if(flag==1)
 86         {
 87             printf("No solution\n");
 88             continue;
 89         }
 90         memset(dp,0,sizeof(dp));
 91         dp[0][0]=1;
 92         for(i=1;i<=m;i++)
 93         {
 94             for(j=n/2;j>=0;j--)
 95             if(dp[i-1][j])
 96             {
 97                 dp[i][j+s1[i][0]]=1;
 98                 dp[i][j+s2[i][0]]=2;
 99             }
100         }
101         for(j=n/2;j>=0;j--)
102         {
103             if(dp[m][j]) break;
104         }/*找点数和离n/2最近的一个组合*/
105         k1=0;
106         for(i=m;i>=1;i--)
107         {
108             if(dp[i][j]==1)
109             {
110                 j-=s1[i][0];
111                 for(h=1;h<=s1[i][0];h++)
112                     pre1[++k1]=s1[i][h];
113             }
114             else 
115             {
116                 j-=s2[i][0];
117                 for(h=1;h<=s2[i][0];h++)
118                     pre1[++k1]=s2[i][h];
119             }
120         }
121         memset(visit,0,sizeof(visit));
122         printf("%d",k1);
123         for(i=1;i<=k1;i++)
124         {
125             printf(" %d",pre1[i]);
126             visit[pre1[i]]=1;
127         }
128         printf("\n");
129         printf("%d",n-k1);
130         for(i=1;i<=n;i++)
131         {
132             if(visit[i]==0)
133             printf(" %d",i);
134         }
135         printf("\n");
136     }
137     return 0;
138 }

 

posted on 2011-04-14 10:18  奋斗青春  阅读(366)  评论(0编辑  收藏  举报