zoj 1462Team Them Up!

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

题意很简单:

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 }

 

你可能感兴趣的:(ZOJ)