bzoj3280: 小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]
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
Case 2: impossible
HINT
样例解释:买下90块钱的那40个研究生,另外再买10个100块钱的。这样,第一天用完的10个人全部送到医院,那么他们在第三天可以继续使用;同时,第二天和第三天都用新的研究生来弥补,这样一共需要花费40*90
+ 10*100 + 5*10 =
4650元。
数据规模:
对于30%的数据中的每组数据,
满足n<=5,m,k<=2,其余数均小于等于100或者
n<=10,m,k<=10,其余数均小于等于20.
对于100%的数据
n,m,k<=50,其余数均小于等于100.
题解:
先要将每一天拆成两个点分别表示这天开始和结束
由S向第一天的开始练m条边,容量和费用分别为每个学校的学生个数和单价,表示要买多少学生和所需的费用
由每天开始向T连容量为每天所需的学生个数,费用为0,表示这天要用这么多的学生
由每天开始向下一天开始连容量为inf,费用为0的边,表示这天没有用到的学生可以留到下一天用
由S向每天的结束连容量为每天所需的学生个数,费用为0,表示这天用过的并且要去复活的学生
对于每个医院(d,q),由第i天的结束节点向第i+d+1天的开始节点连容量为inf,费用为q的边,表示把这些学生复活
然后跑遍费用流即可,如果最大流=总共所需学生数量则有解,否则无解
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 105 7 #define maxm 20300 8 #define inf 1061109567 9 using namespace std; 10 char ch; 11 bool ok; 12 void read(int &x){ 13 ok=0; 14 for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 15 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 16 if (ok) x=-x; 17 } 18 int T,n,m,k,x,y,sum; 19 struct costflow{ 20 int s,t,tot,now[maxn],son[maxm],pre[maxm],val[maxm],cost[maxm]; 21 int dis[maxn],tmp,totflow,totcost,sla[maxn],head,tail,list[maxn],path[maxn]; 22 bool bo[maxn]; 23 void init(){s=0,t=(n<<1)+1,tot=1,memset(now,0,sizeof(now));} 24 void put(int a,int b,int c,int d){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c,cost[tot]=d;} 25 void add(int a,int b,int c,int d){put(a,b,c,d),put(b,a,0,-d);} 26 int dfs(int u,int rest,int totval){ 27 if (u==t){totcost+=rest*totval;return rest;} 28 int ans=0; bo[u]=1; 29 for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p]) 30 if (val[p]&&!bo[v]){ 31 int t=dis[u]+cost[p]-dis[v]; 32 if (!t){ 33 int d=dfs(v,min(rest,val[p]),totval+cost[p]); 34 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d; 35 } 36 else sla[v]=min(sla[v],t); 37 } 38 return ans; 39 } 40 bool relax(){ 41 int d=inf; 42 for (int u=s;u<=t;u++) if (!bo[u]) d=min(d,sla[u]); 43 if (d==inf) return false; 44 for (int u=s;u<=t;u++) if (!bo[u]) dis[u]+=d; 45 return true; 46 } 47 void work(){ 48 memset(dis,0,sizeof(dis)),totflow=totcost=0; 49 do{ 50 memset(sla,63,sizeof(sla)); 51 do{ 52 memset(bo,0,sizeof(bo)); 53 tmp=dfs(s,inf,0),totflow+=tmp; 54 }while (tmp); 55 }while (relax()); 56 } 57 }f; 58 int main(){ 59 int Case=0; 60 for (read(T);T;T--){ 61 read(n),read(m),read(k),f.init(),sum=0,Case++; 62 for (int i=1;i<=n;i++) read(x),sum+=x,f.add(i,f.t,x,0),f.add(f.s,i+n,x,0); 63 for (int i=1;i<n;i++) f.add(i,i+1,inf,0); 64 for (int i=1;i<=m;i++) read(x),read(y),f.add(f.s,1,x,y); 65 for (int i=1;i<=k;i++){ 66 read(x),read(y); 67 for (int j=1;j<=n-x-1;j++) f.add(j+n,j+x+1,inf,y); 68 } 69 f.work(); 70 printf("Case %d: ",Case); 71 if (f.totflow==sum) printf("%d\n",f.totcost); 72 else puts("impossible"); 73 } 74 return 0; 75 }