Student's Morning

sgu242:http://acm.sgu.ru/problem.php?contest=0&problem=242

题意:把n个人分到m组,每一组至少2个人,每个人只能属于一个组。一开始把题目读错了,以为这n个必须都要有一个组,实际上,有些人可以不应分组,直接留在家里,这样就简单许多。

题解:把问题简化一下就是每个学校分2个人,如果这个条件都满足不了的话,就不可能满足。所以建图的时候s-->学校,容量是2,学校到人,容量是1,然后人到t,容量是1,这里是不需要的拆点的,因为上诉的建图凡是已经把正每个人只会属于一个组,只会被应一次。所以直接跑网络流就好,然后输出即可。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<queue>
  6 #define INF 100000000
  7 using namespace std;
  8 const int N=605;
  9 const int M=100000;
 10 struct Node{
 11    int v;
 12    int f;
 13    int next;
 14 }edge[M];
 15 int n,m,u,v,cnt,sx,ex;
 16 int head[N],pre[N];
 17 int val[N][40];//根据题目要求申请
 18 void init(){
 19     cnt=0;
 20     memset(head,-1,sizeof(head));
 21 }
 22 void add(int u,int v,int w){
 23     edge[cnt].v=v;
 24     edge[cnt].f=w;
 25     edge[cnt].next=head[u];
 26     head[u]=cnt++;
 27     edge[cnt].f=0;
 28     edge[cnt].v=u;
 29     edge[cnt].next=head[v];
 30     head[v]=cnt++;
 31 }
 32 bool BFS(){
 33   memset(pre,0,sizeof(pre));
 34   pre[sx]=1;
 35   queue<int>Q;
 36   Q.push(sx);
 37  while(!Q.empty()){
 38      int d=Q.front();
 39      Q.pop();
 40      for(int i=head[d];i!=-1;i=edge[i].next    ){
 41         if(edge[i].f&&!pre[edge[i].v]){
 42             pre[edge[i].v]=pre[d]+1;
 43             Q.push(edge[i].v);
 44         }
 45      }
 46   }
 47  return pre[ex]>0;
 48 }
 49 int dinic(int flow,int ps){
 50     int f=flow;
 51      if(ps==ex)return f;
 52      for(int i=head[ps];i!=-1;i=edge[i].next){
 53         if(edge[i].f&&pre[edge[i].v]==pre[ps]+1){
 54             int a=edge[i].f;
 55             int t=dinic(min(a,flow),edge[i].v);
 56               edge[i].f-=t;
 57               edge[i^1].f+=t;
 58             flow-=t;
 59              if(flow<=0)break;
 60         }
 61 
 62      }
 63       if(f-flow<=0)pre[ps]=-1;
 64       return f-flow;
 65 }
 66 int solve(){
 67     int sum=0;
 68     while(BFS())
 69         sum+=dinic(INF,sx);
 70     return sum;
 71 }
 72 int main() {
 73     int T,k,temp,sum,tt=1;
 74     while(~scanf("%d%d",&n,&m)) {
 75          sum=0;
 76          init();
 77         for(int i=1; i<=n; i++) {
 78             scanf("%d",&T);
 79             while(T--){
 80                 scanf("%d",&temp);
 81                 add(temp,i+m,1);
 82             }
 83             add(i+m,n+m+1,1);
 84         }
 85        for(int j=1;j<=m;j++)
 86          add(0,j,2);
 87          sx=0,ex=n+m+1;
 88          if(solve()<2*m)puts("NO\n");
 89          else{
 90             printf("YES\n");
 91             for(int i=1;i<=m;i++){
 92                 printf("2");
 93                 for(int j=head[i];j!=-1;j=edge[j].next){
 94                     if(edge[j].f==0)//这里不是f>0,而是f==0才是满流的标志,注意和邻接矩阵的区别
 95                         printf(" %d",edge[j].v-m);
 96                 }
 97                 puts("");
 98             }
 99          }
100     }
101     return 0;
102 }
View Code

 

posted on 2014-09-01 10:19  天依蓝  阅读(142)  评论(0编辑  收藏  举报

导航