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

Sample Output

Case 1: 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();
    }
}

 

posted @ 2018-06-03 09:17  fcwww  阅读(195)  评论(0编辑  收藏  举报