您的位置:首页 > 其它

BZOJ 3280: 小R的烦恼 & BZOJ 1221: [HNOI2001] 软件开发

2017-01-09 12:18 411 查看

3280: 小R的烦恼

Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 399 Solved: 200
[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

接着一行2m个数,表示l[1],p[1]…l
,p

接着一行2k个数,表示d[1],q[1]…d
,q

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.

Source

网络流

分析:

我们把每一天拆成两个点,一个叫做A集合,一个叫做B集合...从S向A集合的每个点连一条容量为a[i]费用为0的边,从B集合中的每个点向T连边...

然后对于每个大学,从当前大学向每个B集合中的点连一条容量为inf费用为0的边,从S向每个大学连一条容量为l[i]费用为p[i]的边...

然后A集合中的每个点向B集合中的对应点+d[x]+1的点连一条容量为inf费用为q[x]的边,然后每个B集合中的点向下一天的点连边...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
//by NeighThorn
#define inf 0x3f3f3f3f
using namespace std;

const int maxn=200+5,maxm=20000+5;

int c,n,m,k,S,T,ans,sum,cas,cnt,w[maxm],hd[maxn],fl[maxm],to[maxm],nxt[maxm],dis[maxn],Min[maxn],vis[maxn],from[maxn];

inline bool spfa(void){
memset(dis,inf,sizeof(dis));
memset(Min,inf,sizeof(Min));
queue<int> q;q.push(S),vis[S]=1,dis[S]=0;
while(!q.empty()){
int top=q.front();q.pop();vis[top]=0;
for(int i=hd[top];i!=-1;i=nxt[i])
if(dis[to[i]]>dis[top]+w[i]&&fl[i]){
from[to[i]]=i;
dis[to[i]]=dis[top]+w[i];
Min[to[i]]=min(Min[top],fl[i]);
if(!vis[to[i]])
vis[to[i]]=1,q.push(to[i]);
}
}
return dis[T]!=inf;
}

inline int find(void){
for(int i=T;i!=S;i=to[from[i]^1])
fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T];
return ans+=Min[T],dis[T]*Min[T];
}

inline int mcmf(void){
int res=0;
while(spfa())
res+=find();
return res;
}

inline void add(int l,int s,int x,int y){//cout<<x<<" "<<y<<" "<<s<<" "<<l<<endl;
w[cnt]=l;fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
w[cnt]=-l;fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
}

signed main(void){
scanf("%d",&cas);
while(cas--){cnt=0;c++;sum=ans=0;
scanf("%d%d%d",&n,&m,&k);S=0;
memset(hd,-1,sizeof(hd));T=n*2+m+1;
for(int i=1,x;i<=n;i++){
scanf("%d",&x),add(0,x,S,i+n),add(0,x,i,T);sum+=x;
if(i+1<=n)
add(0,inf,i,i+1);
}
for(int i=1,x,y;i<=m;i++){
scanf("%d%d",&x,&y),add(y,x,S,2*n+i);
for(int j=1;j<=n;j++)
add(0,inf,2*n+i,j);
}
for(int i=1,x,y;i<=k;i++){
scanf("%d%d",&x,&y);x++;
for(int j=1;j<=n;j++){
int lala=j+x;
if(lala<=n)
add(y,inf,j+n,lala);
}
}int lala=mcmf();
printf("Case %d: ",c);
if(ans!=sum)
puts("impossible");
else
printf("%d\n",lala);
}
return 0;
}


1221: [HNOI2001] 软件开发

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1454 Solved: 805
[Submit][Status][Discuss]

Description

某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员每天提供一块消毒毛巾,这种消毒毛巾使用一天后必须再做消毒处理后才能使用。消毒方式有两种,A种方式的消毒需要a天时间,B种方式的消毒需要b天(b>a),A种消毒方式的费用为每块毛巾fA, B种消毒方式的费用为每块毛巾fB,而买一块新毛巾的费用为f(新毛巾是已消毒的,当天可以使用);而且f>fA>fB。公司经理正在规划在这n天中,每天买多少块新毛巾、每天送多少块毛巾进行A种消毒和每天送多少块毛巾进行B种消毒。当然,公司经理希望费用最低。你的任务就是:为该软件公司计划每天买多少块毛巾、每天多少块毛巾进行A种消毒和多少毛巾进行B种消毒,使公司在这项n天的软件开发中,提供毛巾服务的总费用最低。

Input

第1行为n,a,b,f,fA,fB. 第2行为n1,n2,……,nn. (注:1≤f,fA,fB≤60,1≤n≤1000)

Output

最少费用

Sample Input

4 1 2 3 2 1

8 2 1 6

Sample Output

38

HINT

Source

分析:

和上一题差不多...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
//by NeighThorn
#define inf 0x3f3f3f3f
using namespace std;

const int maxn=2000+5,maxm=maxn*maxn;

int n,a,b,f,fa,fb,S,T,cnt,w[maxm],hd[maxn],to[maxm],fl[maxm],nxt[maxm],dis[maxn],Min[maxn],vis[maxn],from[maxn];

inline bool spfa(void){
memset(dis,inf,sizeof(dis));
memset(Min,inf,sizeof(Min));
queue<int> q;q.push(S),vis[S]=1,dis[S]=0;
while(!q.empty()){
int top=q.front();q.pop();vis[top]=0;
for(int i=hd[top];i!=-1;i=nxt[i])
if(dis[to[i]]>dis[top]+w[i]&&fl[i]){
from[to[i]]=i;
dis[to[i]]=dis[top]+w[i];
Min[to[i]]=min(Min[top],fl[i]);
if(!vis[to[i]])
vis[to[i]]=1,q.push(to[i]);
}
}
return dis[T]!=inf;
}

inline int find(void){
for(int i=T;i!=S;i=to[from[i]^1])
fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T];
return dis[T]*Min[T];
}

inline int mcmf(void){
int res=0;
while(spfa())
res+=find();
return res;
}

inline void add(int l,int s,int x,int y){
w[cnt]=l;fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
w[cnt]=-l;fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++;
}

signed main(void){
memset(hd,-1,sizeof(hd));S=0;
scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&fa,&fb);T=2*n+1;
for(int i=1,x;i<=n;i++){
scanf("%d",&x),add(0,x,S,i),add(0,x,i+n,T);
if(i<n)
add(0,inf,i+n,i+n+1);
int lala=i+a+1,lalala=i+b+1;
if(lala<=n)
add(fa,inf,i,lala+n);
if(lalala<=n)
add(fb,inf,i,lalala+n);
}add(f,inf,S,1+n);
printf("%d\n",mcmf());
return 0;
}//Cap ou pas cap. Pas cap.


By NeighThorn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: