BZOJ_3280_小R的烦恼_最小费用最大流
BZOJ_3280_小R的烦恼_最小费用最大流
Description
小R最近遇上了大麻烦,他的程序设计挂科了。于是他只好找程设老师求情。善良的程设老师答应不挂他,但是要
求小R帮助他一起解决一个难题。问题是这样的,程设老师最近要进行一项邪恶的实验来证明P=NP,这个实验一共
持续n天,第i天需要a[i]个研究生来给他搬砖。研究生毕竟也是人,所以雇佣研究生是需要钱的,机智的程设老师
已经联系好了m所大学,第j所大学共有l[j]个研究生,同时雇佣这所大学的一个研究生需要p[j]元钱。本来程设老
师满心欢喜的以为,这样捡最便宜的max{a[i]}个研究生雇来,就可以完成实验;结果没想到,由于他要求硕士生
们每天工作25个小时不许吃饭睡觉上厕所喝水说话咳嗽打喷嚏呼吸空气,因此一天下来给他搬砖的所有研究生都会
进入濒死状态。濒死状态的研究生,毫无疑问,就不能再进行工作了。但是机智的老师早早联系好了k家医院,第i
家医院医治一个濒死的研究生需要d[i]天,并且需要q[i]元钱。现在,程设老师想要知道,最少花多少钱,能够在
这n天中满足每天的需要呢?若无法满足,则请输出”impossible”。注意,由于程设老师良心大大的坏,所以他
是可以不把濒死的研究生送去医院的!。
Input
本题包含多组数据;第一行是一个数T(T<=11),表示数据组数,以下T组数据。
对于每一组数据,第一行三个数,n,m,k;
以下一行n个数,表示a[1]…a[n]
接着一行2m个数,表示l[1],p[1]…l[n],p[n]
接着一行2k个数,表示d[1],q[1]…d[n],q[n]
n,m,k<=50,其余数均小于等于100.
Output
对于每组数据以样例的格式输出一行,两个数分别表示第几组数据和最少钱数。
Sample Input
2
3 2 1
10 20 30
40 90 15 100
1 5
3 2 1
10 20 30
40 90 15 100
2 5
3 2 1
10 20 30
40 90 15 100
1 5
3 2 1
10 20 30
40 90 15 100
2 5
Sample Output
Case 1: 4650
Case 2: impossible
样例解释:
买下90块钱的那40个研究生,另外再买10个100块钱的。这样,第一天用完的10个人全部送到医院,那么他们在第
三天可以继续使用;同时,第二天和第三天都用新的研究生来弥补,这样一共需要花费40*90 + 10*100 + 5*10 =
4650元。
Case 2: impossible
样例解释:
买下90块钱的那40个研究生,另外再买10个100块钱的。这样,第一天用完的10个人全部送到医院,那么他们在第
三天可以继续使用;同时,第二天和第三天都用新的研究生来弥补,这样一共需要花费40*90 + 10*100 + 5*10 =
4650元。
类似餐巾计划问题,将人拆成两个点(i,i')分别表示活的和死的。
对学校有S->1(l[j],p[j])。对于第i天剩下的:S->i'(a[i],0)。
i->i+1(inf,0) i'-i'+1(inf,0) 医院:i'->i+d[i](inf,q[i]) 流出去:i->T(a[i],0)。
代码:
#include <cstdio> #include <string.h> #include <algorithm> using namespace std; #define N 1050 #define M 1000050 #define S (n+n+1) #define T (n+n+2) #define inf 1<<30 int head[N],to[M],nxt[M],val[M],flow[M],cnt,n,m,K,a_[N],l_[N],p_[N],d_[N],q_[N]; int Q[N],l,r,dis[N],inq[N],path[N],sum,TTT; inline void add(int u,int v,int f,int c) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; val[cnt]=c; to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; val[cnt]=-c; } bool spfa() { memset(dis,0x3f,sizeof(dis)); memset(path,0,sizeof(path)); l=r=0; Q[r++]=S; dis[S]=0; inq[S]=1; while(l!=r) { int x=Q[l++],i;inq[x]=0; if(l==T) l=0; for(i=head[x];i;i=nxt[i]) { if(dis[to[i]]>dis[x]+val[i]&&flow[i]) { dis[to[i]]=dis[x]+val[i]; path[to[i]]=i^1; if(!inq[to[i]]) { inq[to[i]]=1; Q[r++]=to[i]; if(r==T) r=0; } } } } return path[T]; } void mcmf() { TTT++; int maxf=0,minc=0; while(spfa()) { int i,nf=1<<30; for(i=T;i!=S;i=to[path[i]]) { nf=min(nf,flow[path[i]^1]); } maxf+=nf; for(i=T;i!=S;i=to[path[i]]) { minc+=nf*val[path[i]^1]; flow[path[i]]+=nf; flow[path[i]^1]-=nf; } } // printf("%d %d %d\n",maxf,minc,sum); if(maxf<sum) { printf("Case %d: impossible\n",TTT); }else { printf("Case %d: %d\n",TTT,minc); } } void solve() { memset(head,0,sizeof(head)); cnt=1; sum=0; int i,j; scanf("%d%d%d",&n,&m,&K); for(i=1;i<=n;i++) scanf("%d",&a_[i]),add(i,T,a_[i],0),sum+=a_[i],add(S,i+n,a_[i],0); for(i=1;i<=m;i++) scanf("%d%d",&l_[i],&p_[i]),add(S,1,l_[i],p_[i]); for(i=1;i<=K;i++) scanf("%d%d",&d_[i],&q_[i]); for(i=1;i<=n;i++) { if(i!=n) add(i,i+1,inf,0),add(i+n,i+n+1,inf,0); for(j=1;j<=K;j++) { if(i+d_[j]+1<=n) add(i+n,i+d_[j]+1,inf,q_[j]); } } mcmf(); } int main() { int cs; scanf("%d",&cs); while(cs--) { solve(); } }