luogu2891 [USACO07OPEN]吃饭Dining

题目大意:

有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。

解题方法:

这题算是网络流入门题,主要考如何构图,将食物置于左侧,牛置于中间,饮料置于右侧,依次连边,这样会发现无法满足每头牛只享用最多一种食物和一种饮料的条件。

所以可将中间的每个牛拆成两个点,两点之间连一条流量为1的边,最后源点向所有食物连流量为1的边,所以饮料向汇点连流量为1的边,跑网络流即可。

代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<cstdlib>
  6 #include<algorithm>
  7 #include<queue>
  8 using namespace std;
  9 const int MAXN=11000;
 10 const int INF=0x7fffffff;
 11 struct Edge
 12 {
 13     int v,c,next;
 14 }ed[MAXN*20];
 15 int n,f,d;
 16 int dis[MAXN];
 17 int nume=-1,head[MAXN]={0},cru[MAXN]={0};
 18 void add_edge(int u,int v,int c)
 19 {
 20     nume++;
 21     ed[nume].v=v;
 22     ed[nume].c=c;
 23     ed[nume].next=head[u];
 24     head[u]=nume;
 25     nume++;
 26     ed[nume].v=u;
 27     ed[nume].c=0;
 28     ed[nume].next=head[v];
 29     head[v]=nume;
 30 }
 31 bool BFS(int s,int t)
 32 {
 33     queue<int> team;
 34     team.push(s);
 35     memset(dis,0,sizeof(dis));
 36     dis[s]=1;
 37     while(!team.empty())
 38     {
 39         int u=team.front();
 40         team.pop();
 41         for(int i=head[u];i+1;i=ed[i].next)
 42         if(!dis[ed[i].v] && ed[i].c>0)
 43         {
 44             dis[ed[i].v]=dis[u]+1;
 45             team.push(ed[i].v);
 46         }
 47     }
 48     return dis[t];
 49 }
 50 int DFS(int now,int t,int flow)
 51 {
 52     if(now==t) return flow;
 53     int s=0,k;
 54     for(int &i=cru[now];i+1;i=ed[i].next)
 55     {
 56         int to=ed[i].v;
 57         if(ed[i].c>0 && dis[to]==dis[now]+1)
 58         {
 59             k=DFS(to,t,min(flow-s,ed[i].c));
 60             s+=k;
 61             ed[i].c-=k;ed[i^1].c+=k;
 62             if(s==flow) break;
 63         }
 64     }
 65     if(s==0) dis[now]=0;
 66     return s;
 67 }
 68 int Dinic(int s,int t)
 69 {
 70     int ans=0;
 71     while(BFS(s,t))
 72     {
 73         memcpy(cru,head,sizeof(head));
 74         ans+=DFS(s,t,INF);
 75     }
 76     return ans; 
 77 }
 78 int main()
 79 {
 80     int s,t;
 81     scanf("%d%d%d",&n,&f,&d);
 82     s=0;t=n*2+f+d;
 83     memset(head,-1,sizeof(head));
 84     for(int i=1;i<=f;i++) add_edge(s,i,1);
 85     for(int i=1;i<=n;i++) add_edge(f+i,f+i+n,1);
 86     for(int i=1;i<=d;i++) add_edge(2*n+f+i,t,1);
 87     for(int i=1;i<=n;i++)
 88     {
 89         int numf,numd;
 90         scanf("%d%d",&numf,&numd);
 91         int x;
 92         for(int j=1;j<=numf;j++)
 93         {
 94             scanf("%d",&x);
 95             add_edge(x,i+f,1);
 96         }
 97         for(int j=1;j<=numd;j++)
 98         {
 99             scanf("%d",&x);
100             add_edge(n+i+f,2*n+f+x,1);
101         }
102     }
103     printf("%d",Dinic(s,t));
104     return 0;
105 }
View Code

 

posted @ 2018-10-05 08:10  Oracle_LinJH  阅读(80)  评论(0编辑  收藏  举报