最初读完这道题目之后,完全没有什么想法,也根本不会想到用最大流的做法。因为题目的条件似乎很多变:每个顾客打开自己的猪笼后,可以随时变换里面猪的数量,这个条件就给思考上带来了一定难度。
后来到网上看了一下题解,才发现建图是关键。具体建图的思路和过程,详见:http://imlazy.ycool.com/post.2059102.html。只要你知道最大流是干什么的,这个题解肯定能够看懂。
总结:
1、建图:
如果一道题目看出来是最大流,可能一开始建图会很麻烦,但是要在麻烦的建图中,找到简化建图的方案。就像上面的题解一样,简化到最大流算法可以接受的复杂度范围内,然后再从简化的建图中,去找建图的规律。这一步也是做出这道题目的关键。
2、最大流算法中的细节问题:
(1)、在初始化建图的时候,一定要记得把源点和汇点先放在变量里面,这样可以省去后面如果发现问题,改变源点和汇点的麻烦。
(2)、我的sap模板中,st,ed就不用说了,cnt是个数+1,因为所有点是从0开始计算的。
(3)、sap的参数尽量不要用n,用cnt吧。
(4)、sap函数中的第一个循环中的i,不要用int。
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 111;
const int maxm = maxn * maxn;
const int inf = 1 << 29;
int n, m;
struct node
{
int c, to, next;
}edge[maxm];
int head[maxn];
int num[maxm];
bool visit[maxm];
int sm;
void add_edge(int u, int v, int cap)
{
edge[sm].to = v, edge[sm].c = cap, edge[sm].next = head[u];
head[u] = sm ++;
edge[sm].to = u, edge[sm].c = 0, edge[sm].next = head[v];
head[v] = sm ++;
}
int sap(int st, int ed, int cnt)
{
int numh[maxn], h[maxn], curedge[maxn], pre[maxn];
int cur_flow, ans = 0, u, tmp, neck, i;
memset(h, 0, sizeof(h));
memset(numh, 0, sizeof(numh));
memset(pre, -1, sizeof(pre));
for(i = 0; i <= cnt; i ++)
curedge[i] = head[i];
numh[0] = cnt;
u = st;
while(h[st] < cnt)
{
if(u == ed)
{
cur_flow = inf;
for(i = st; i != ed; i = edge[curedge[i]].to)
if(cur_flow > edge[curedge[i]].c)
{
neck = i;
cur_flow = edge[curedge[i]].c;
}
for(i = st; i != ed; i = edge[curedge[i]].to)
{
tmp = curedge[i];
edge[tmp].c -= cur_flow;
edge[tmp^1].c += cur_flow;
}
ans += cur_flow;
u = neck;
}
for(i = curedge[u]; i != -1; i = edge[i].next)
if(edge[i].c && h[u] == h[edge[i].to] + 1)
break;
if(i != -1)
{
curedge[u] = i;
pre[edge[i].to] = u;
u = edge[i].to;
}
else
{
if(--numh[h[u]] == 0)
break;
curedge[u] = head[u];
for(tmp = cnt, i = head[u]; i != -1; i = edge[i].next)
if(edge[i].c)
tmp = min(tmp, h[edge[i].to]);
h[u] = tmp + 1;
++ numh[h[u]];
if(u != st)
u = pre[u];
}
}
return ans;
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
memset(head, -1, sizeof(head));
memset(visit, false, sizeof(visit));
int pre[maxm];
sm = 0;
int st = 0, ed = m + 1;
for(int i = 1; i <= n; i ++)
scanf("%d", &num[i]);
for(int i = 1; i <= m; i ++)
{
int k, key;
scanf("%d", &k);
while(k --)
{
scanf("%d", &key);
if(!visit[key])
{
add_edge(st, i, num[key]);
visit[key] = true;
}
else
add_edge(pre[key], i, inf);
pre[key] = i;
}
int amount;
scanf("%d", &amount);
add_edge(i, ed, amount);
}
int res = sap(st, ed, ed + 1);
printf("%d\n", res);
}
}