bzoj 3280(费用流)

3280: 小R的烦恼

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 307   Solved: 157
[ Submit][ Status][ Discuss]

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

Sample Output

Case 1: 4650
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.


解题思路:与餐巾计划相同。简单建图


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int len,n,m,k,S,T,poo,sum,ans;
int from[200001],next[200001],to[200001],h[200001],f[200001],w[200001];
int dis[160],q[10000000],pre[160];
bool b[160]; 
const int INF=0x7fffffff;


inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' ||y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0'&&y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}


void insert(int x,int y,int flow,int v)
 {
  ++len; from[len]=x; to[len]=y; f[len]=flow; w[len]=v; next[len]=h[x]; h[x]=len;
 }


bool spfa()
 {
  memset(dis,0x7f,sizeof(dis)); dis[S]=0;
  memset(b,true,sizeof(b)); b[S]=false; 
  int tail=1,head=0; q[tail]=S;
  while (head<tail)
  {
  ++head;
  int u=h[q[head]];
  while (u!=0)
  {
    if (f[u]>0 && dis[to[u]]>dis[q[head]]+w[u])
     {
      dis[to[u]]=dis[q[head]]+w[u];
      pre[to[u]]=u;
      if (b[to[u]])
      {
      b[to[u]]=false;
      ++tail; q[tail]=to[u];
  }
 }
    u=next[u];
}
b[q[head]]=true;
 }
if (dis[T]<10000000) return true;else return false;
 }


void mcf()
 {
  int now=T; int mx=0x7fffffff;
  while (now!=S)
  {
  mx=min(mx,f[pre[now]]);
  now=from[pre[now]];
}
poo+=mx; now=T;
while (now!=S)
{
ans+=mx*w[pre[now]];
f[pre[now]]-=mx; f[pre[now]^1]+=mx;
now=from[pre[now]];
}
 }


int main()
{
freopen("me.out","w",stdout);
int tg=read();
for (int t=1;t<=tg;++t)
{
memset(h,0,sizeof(h)); len=1;
n=read(); m=read(); k=read(); S=0; T=101; sum=0;
for (int i=1;i<=n;++i)
{
int x=read(); sum+=x;
insert(S,i,x,0); insert(i,S,0,0);
insert(i+n,T,x,0); insert(T,i+n,0,0);
if (i!=n){insert(i+n,i+n+1,INF,0);insert(i+n+1,i+n,0,0);}
 }
for (int i=1;i<=m;++i)
{
int x,y; x=read(); y=read();
insert(S,n+1,x,y); insert(n+1,S,0,-y);
}
for (int i=1;i<=k;++i)
{
int x,y; x=read(); y=read();
for (int j=1;j<=n;++j)
{
if (j+x+1<=n)
{
insert(j,n+j+x+1,INF,y); insert(n+j+x+1,j,0,-y);
 }
}
}
while (spfa())
{
mcf();
}
printf("Case %d: ",t);
if (poo!=sum)
{
printf("impossible\n");
}else printf("%d\n",ans);
}
}

你可能感兴趣的:(bzoj 3280(费用流))