网络流(建图是重点)
题意:
有一个卖猪的农夫,他有n个猪圈,但是猪圈的钥匙不在他的手上,有m个顾客,每一个顾客会带一些猪圈的钥匙,每一个顾客都有自己想买猪的数量,当然他所带的钥匙能开启相应的猪圈,从而能买到相应的猪,不过有时猪比他想买的数量多,也有可能少。而农夫有一个权力,就是如果某一个顾客没有买完他开的猪圈里的猪,农夫可以把剩下的猪随意的转移在被这个顾客的开启的猪圈里面。求出农夫最多能卖多少猪?
思路:
切入点应该是“转移”字眼吧,意味着可以用网络流解决问题,因为没有花费的存在,那么就是最大流。
我们知道网络流难点是在于把问题抽象成网络,进而建图。
因为我做的网络流不是很多,不过这道题教会了我一个方法去建图,先把所有条件列在纸上,在纸上试着根据题意建一个图,根据题意的意思是有很多限制条件而重点就是在限制条件上建图,然后手动跑一边网络流看看时都能得到结果。如果能得到,那么很可能就是对的建图。
这道题的建图方式就是:猪圈的猪的限制条件是顾客,我们把源点与猪圈连成边,猪圈和顾客连成边,因为猪圈可能会有多个顾客访问,我们只连最先访问的顾客,如果有多个顾客访问这个猪圈,就把剩下的顾客与第一次访问的顾客相连成边,流量是无限大,这意味着前边顾客买不完的猪可以让后边的顾客买。
最后每一个顾客与汇点连成边流量是顾客买猪的最大值。
- 注意点:顾客与顾客之间建图的时候,注意重边,就是顾客与顾客之间最多建一次就行了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 2005;
const int INF = 0x3f3f3f3f;
struct edge
{
int to,cap,rev;
};
int n,m;
vector<edge>G[maxn];
int pignum[maxn];
int vis[maxn];
int level[maxn],iter[maxn];
void add_edge(int from,int to,int cap)
{
int length = G[from].size();
int length1 = G[to].size();
G[from].push_back((edge){to,cap,length1});
G[to].push_back((edge){from,0,length});
}
void bfs(int s)
{
memset(level,-1,sizeof(level));
queue<int>Q;
Q.push(s);
level[s] = 0;
while(!Q.empty()) {
int to = Q.front();
Q.pop();
int length = G[to].size();
for(int i = 0;i < length; i++) {
edge &e = G[to][i];
if(e.cap > 0 && level[e.to] < 0) {
level[e.to] = level[to] + 1;
Q.push(e.to);
}
}
}
}
int dfs(int u,int t,int f)
{
if(u == t) return f;
else {
int length = G[u].size();
for(int &i = iter[u];i < length; i++) {
edge &e = G[u][i];
if(e.cap > 0 && level[e.to] > level[u]) {
int d = dfs(e.to,t,min(f,e.cap));
if(d > 0) {
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int flow = 0;
for(;;) {
bfs(s);
if(level[t] < 0)
break;
memset(iter,0,sizeof(iter));
int f;
while((f = dfs(s,t,INF)) > 0) {
flow += f;
}
}
return flow;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i = 1;i <= n; i++) {
scanf("%d",&pignum[i]);
add_edge(0,i,pignum[i]);
}
for(int i = n+1;i <= n+m; i++) {
int pighouse;
scanf("%d",&pighouse);
for(int k = 0;k < pighouse; k++) {
int pig;
scanf("%d",&pig);
if(vis[pig] == 0) {
vis[pig] = true;
add_edge(pig,i,pignum[pig]);
}
else {
int uppeople = G[pig][1].to;
int length = G[uppeople].size();
int flag = true;
for(int j = 0;j < length; j++) {
if(G[uppeople][j].to == i) {
flag = false;
break;
}
}
if(flag) {
add_edge(uppeople,i,INF);
}
}
}
int sum;
scanf("%d",&sum);
add_edge(i,n+m+1,sum);
}
printf("%d\n",max_flow(0,n+m+1));
return 0;
}