POJ 1149(最大流)

这道题应该都能想到朴素的有n*m+个点的建图方案吧,呵呵,显然是不行的。

那么怎么办?

其实我们可以这样想:一个人能买到的猪有两个来源:

①来自自己第一次打开的猪圈

②来自之前别人打开的猪圈

想到了这个实质,见图就简单了!

我们设一个超级源点S,和超级汇点T,对于每一个人,从S向他连一条容量为K的边(K是由这个人第一次打开的猪圈的初始猪的个数之和),然后对于一个人A,他打开了P猪圈,

且P猪圈之前被B打开过,则从B向A连一条容量为INF的边,最后,对于每一个人,都向T连一条容量为lim[i](表示每个人的购买猪的上限)的边,跑在最大流就行!

代码:

View Code
 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <iostream>
 5 #define N 2010
 6 #define M  200100
 7 #define INF 100000000
 8 using namespace std;
 9 int head[N],next[M],to[M],len[M],cnt,S,T,n,m,layer[N],q[M<<4]; 
10 int cus[N],ini[N],num[N],key[N][N],lim[N],ww[N];
11 inline void add(int u,int v,int w)
12 {
13     to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
14     to[cnt]=u; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++;
15 }
16 void read()
17 {
18     memset(cus,0,sizeof cus);
19     memset(ww,0,sizeof ww);
20     memset(head,-1,sizeof head);
21     cnt=0;
22     S=0; T=n+1;
23     for(int i=1;i<=m;i++) scanf("%d",&ini[i]);
24     for(int i=1;i<=n;i++)
25     {
26         scanf("%d",&num[i]);
27         for(int j=1;j<=num[i];j++)
28         {
29             scanf("%d",&key[i][j]);
30             //cus[i]表示上一次开启i猪圈的人的编号 
31             if(cus[key[i][j]]==0)//i是第一个开key[i][j]猪圈的人
32             { 
33                 ww[i]+=ini[key[i][j]];
34                 cus[key[i][j]]=i;//更新 
35             }
36             else
37             {
38                 add(cus[key[i][j]],i,INF);
39                 cus[key[i][j]]=i;
40             }
41         }
42         scanf("%d",&lim[i]);
43     }
44     for(int i=1;i<=n;i++) add(S,i,ww[i]),add(i,T,lim[i]);
45 }
46 bool bfs()
47 {
48     memset(layer,-1,sizeof layer);
49     int h=1,t=2,sta;
50     q[1]=S; layer[S]=0;
51     while(h<t)
52     {
53         sta=q[h++];
54         for(int i=head[sta];~i;i=next[i])
55             if(len[i]>0&&layer[to[i]]<0)
56             {
57                 layer[to[i]]=layer[sta]+1;
58                 q[t++]=to[i];
59             }
60     }
61     return layer[T]!=-1;
62 }
63 int find(int u,int cur_flow)
64 {
65     if(u==T) return cur_flow;
66     int result=0,tmp;
67     for(int i=head[u];~i&&result<cur_flow;i=next[i])
68         if(len[i]>0&&layer[to[i]]==layer[u]+1)
69         {
70             tmp=find(to[i],min(cur_flow-result,len[i]));
71             len[i]-=tmp; len[i^1]+=tmp; result+=tmp;
72         }
73     if(!result) layer[u]=-1;
74     return result;
75 }
76 int dinic()
77 {
78     int ans=0;
79     while(bfs()) ans+=find(S,INF);
80     return ans;
81 }
82 int main()
83 {
84     while(scanf("%d%d",&m,&n)!=EOF)
85     {
86         read();
87         printf("%d\n",dinic());
88     }
89     return 0;
90 }
没有人能阻止我前进的步伐,除了我自己!
原文地址:https://www.cnblogs.com/proverbs/p/2659317.html