广州的同学看这里:
http://www.gdgzoi.com/JudgeOnline/problem.php?cid=1045&pid=5
Description
Mirko在一家大型养猪场工作,这家养猪场有M间可上锁的猪舍,但Mirko无法对任何一间猪舍上锁,因为他没钥匙。顾客一个接一个地到养猪场来,每个人都有一些猪舍的钥匙,他们要来买一定数量的猪。
每天早晨Mirko 所关心的数据是这一天要来养猪场的顾客,以便Mirko做好销售计划,给出要卖的猪的最大数字。
确切地讲,过程如下:顾客到养猪场,打开所有他有钥匙的猪舍,Mirko从被打开的猪舍里卖一定数量的猪给顾客,并且,如果Mirko需要,他在被打开的猪舍中重新分配剩余的猪。
在每间猪舍中猪的数量没有限制。
请编写程序,给出在一天中,Mirko可以卖出的猪的最大数量。
输入
输入的第一行给出两个整数M和N,1<= M <= 1000,1<=N<=100,分别是猪舍的数量和顾客的数量。猪舍编号从1到M,顾客编号从1到N。
下一行给出M个整数,表示每间猪舍在初始时猪的数量。每间猪舍里猪的数量大于等于0,小于等于1000。
然后的N行按如下形式给出顾客的记录(第i个顾客的记录在第(i+2)行):
A K1 K2 ... KA B 表示顾客拥有的猪舍的钥匙编号为K1,K2,... ,KA(按非递减序排列),并且要买B头猪。数字A和B可以为0。
输出
输出的第一行且唯一的一航给出要卖猪的头数。
样例输入 | 样例输出 |
3 3 3 1 10 2 1 2 2 2 1 3 3 1 2 6 | 7 |
这道题目建图不会很困难,就是有时会想不到
1.要注意顾客是一个接一个的到来的,所以前面的顾客一定要对后面的顾客有影响。
2.我们把一个一个顾客一个接一个加入图中,也猪舍建立联系:
(1) 若该猪舍没有被前面的人打开过,则直接与超源点连接,容量为猪舍中猪的数量。
(2)否则,则找到最近一次打开那个猪舍的人连接,容量为INF。
3.没个顾客与超汇点连接,容量为他需要的猪的数量。
下面有一个图(样例图):
有没有发现每个点都特别有层次感:因为后面的顾客是直接受前面顾客的影响的。
接下来就是贴代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#define maxn 1005
#define INF 10000005
using namespace std;
struct Edge{
int from,to,cap,flow;
Edge(int u,int v,int c,int f) :from(u),to(v),cap(c),flow(f) {}
};
vector<Edge> edges;
vector<int> G[maxn];
int a[maxn];
int p[maxn];
int n,m,pig[maxn];
int flag[maxn];//注意这个flag,它记录打开猪舍的最新的顾客以及该猪舍是否被打开过;
void AddEdge(int from,int to,int cap) {
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
int num=edges.size();
G[from].push_back(num-2);
G[to].push_back(num-1);
}
int Maxflow(int s,int t) {
int flow=0;
for(;;) {
memset(a,0,sizeof(a));
queue<int > Q;
Q.push(s);
a[s]=INF;
while(!Q.empty()) {
int x=Q.front(); Q.pop();
for(unsigned int i=0;i<G[x].size();i++) {
Edge& e=edges[G[x][i]];
if(!a[e.to] && e.cap>e.flow){
p[e.to]=G[x][i];
a[e.to]=min(a[x],e.cap-e.flow);
Q.push(e.to);
}
}
if(a[t]) break;
}
if(!a[t]) break;
for(int u=t;u!=s;u=edges[p[u]].from) {
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
}
flow+=a[t];
}
return flow;
}
//模板
int main()
{std::ios::sync_with_stdio(false);
cin>>m>>n;
for(int i=1;i<=m;i++)
cin>>pig[i];
int k,exp;
for(int i=1;i<=n;i++)
{cin>>k;
for(int j=1;j<=k;j++){
cin>>exp;
if(!flag[exp]) AddEdge(0,i,pig[exp]);//如果没被打开过,见题解2(1);
else AddEdge(flag[exp],i,INF);//打开过,见2(2);
flag[exp]=i;}
cin>>exp;
AddEdge(i,n+1,exp);//与汇点连接,见3
}
cout<<Maxflow(0,n+1)<<endl;
return 0;
}