EK模板,本题关键在于构图。
将顾客作为结点,构图如下:
1.取超级源点和超级汇点;
2.当猪圈被第一次打开时,在源点与当前顾客之间连接一条边,容量为该猪圈的猪的头数;
3.当某个猪圈 不是被第一次打开时,在上一个打开该猪圈的顾客与当前打开该猪圈的顾客之间连接一条边,容量为无穷大;
4.在每个顾客与源点之间连接一条边,容量为该顾客要买猪的头数。
代码如下:
//47ms
#include <iostream>
#include <queue>
using namespace std;
const int INF = 0x7fffffff;
const int mMax = 1005;
const int nMax = 105;
int cap[nMax][nMax], flow[nMax][nMax];
int pre[nMax], dist[nMax];
int min(int a, int b)
{
return a > b ? b : a;
}
int Edmonds_Karp(int sta, int end)
{
int i, curr, max = 0;
memset(flow, 0, sizeof(flow));
while(true)
{
memset(pre, 0, sizeof(pre));
memset(dist, 0, sizeof(dist));
queue<int> Q;
Q.push(sta);
dist[sta] = INF;
pre[sta] = sta;
while(!Q.empty())
{
curr = Q.front();
Q.pop();
for(i = 0; i <= end; i++)
if(!dist[i] && flow[curr][i] < cap[curr][i])
{
dist[i] = min(dist[curr], cap[curr][i] - flow[curr][i]);
pre[i] = curr;
Q.push(i);
}
}
if(dist[end] == 0)
break;
for(i = end; i != sta; i = pre[i])
{
curr = pre[i];
flow[curr][i] += dist[end];
flow[i][curr] -= dist[end];
}
max += dist[end];
}
return max;
}
int main()
{
int m, n, k, i, j, key;
int pighouse[mMax] = {0};
int visit[mMax] = {0};
//freopen("a.txt", "r", stdin);
memset(cap, 0, sizeof(cap));
cin >> m >> n;
for(i = 1; i <= m; i++)
cin >> pighouse[i];
for(i = 1; i <= n; i++)
{
cin >> k;
for(j = 1; j <= k; j++)
{
cin >> key;
if(!visit[key])
cap[0][i] += pighouse[key];//因为顾客可以同时访问几个猪圈,所以源点与该顾客之间的边的容量等于所有这些猪圈的猪的和
else
cap[visit[key]][i] = INF;
visit[key] = i;
}
cin >> key;
cap[i][n+1] = key;
}
cout << Edmonds_Karp(0, n+1) << endl;
return 0;
}