首页 > 代码库 > BZOJ 3280: 小R的烦恼 & BZOJ 1221: [HNOI2001] 软件开发
BZOJ 3280: 小R的烦恼 & BZOJ 1221: [HNOI2001] 软件开发
3280: 小R的烦恼
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 399 Solved: 200
[Submit][Status][Discuss]
Description
现在,程设老师想要知道,最少花多少钱,能够在这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
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 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集合中的点向下一天的点连边...
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<queue> 6 //by NeighThorn 7 #define inf 0x3f3f3f3f 8 using namespace std; 9 10 const int maxn=200+5,maxm=20000+5; 11 12 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]; 13 14 inline bool spfa(void){ 15 memset(dis,inf,sizeof(dis)); 16 memset(Min,inf,sizeof(Min)); 17 queue<int> q;q.push(S),vis[S]=1,dis[S]=0; 18 while(!q.empty()){ 19 int top=q.front();q.pop();vis[top]=0; 20 for(int i=hd[top];i!=-1;i=nxt[i]) 21 if(dis[to[i]]>dis[top]+w[i]&&fl[i]){ 22 from[to[i]]=i; 23 dis[to[i]]=dis[top]+w[i]; 24 Min[to[i]]=min(Min[top],fl[i]); 25 if(!vis[to[i]]) 26 vis[to[i]]=1,q.push(to[i]); 27 } 28 } 29 return dis[T]!=inf; 30 } 31 32 inline int find(void){ 33 for(int i=T;i!=S;i=to[from[i]^1]) 34 fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T]; 35 return ans+=Min[T],dis[T]*Min[T]; 36 } 37 38 inline int mcmf(void){ 39 int res=0; 40 while(spfa()) 41 res+=find(); 42 return res; 43 } 44 45 inline void add(int l,int s,int x,int y){//cout<<x<<" "<<y<<" "<<s<<" "<<l<<endl; 46 w[cnt]=l;fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++; 47 w[cnt]=-l;fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++; 48 } 49 50 signed main(void){ 51 scanf("%d",&cas); 52 while(cas--){cnt=0;c++;sum=ans=0; 53 scanf("%d%d%d",&n,&m,&k);S=0; 54 memset(hd,-1,sizeof(hd));T=n*2+m+1; 55 for(int i=1,x;i<=n;i++){ 56 scanf("%d",&x),add(0,x,S,i+n),add(0,x,i,T);sum+=x; 57 if(i+1<=n) 58 add(0,inf,i,i+1); 59 } 60 for(int i=1,x,y;i<=m;i++){ 61 scanf("%d%d",&x,&y),add(y,x,S,2*n+i); 62 for(int j=1;j<=n;j++) 63 add(0,inf,2*n+i,j); 64 } 65 for(int i=1,x,y;i<=k;i++){ 66 scanf("%d%d",&x,&y);x++; 67 for(int j=1;j<=n;j++){ 68 int lala=j+x; 69 if(lala<=n) 70 add(y,inf,j+n,lala); 71 } 72 }int lala=mcmf(); 73 printf("Case %d: ",c); 74 if(ans!=sum) 75 puts("impossible"); 76 else 77 printf("%d\n",lala); 78 } 79 return 0; 80 }
1221: [HNOI2001] 软件开发
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 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
8 2 1 6
Sample Output
HINT
Source
分析:
和上一题差不多...
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<queue> 6 //by NeighThorn 7 #define inf 0x3f3f3f3f 8 using namespace std; 9 10 const int maxn=2000+5,maxm=maxn*maxn; 11 12 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]; 13 14 inline bool spfa(void){ 15 memset(dis,inf,sizeof(dis)); 16 memset(Min,inf,sizeof(Min)); 17 queue<int> q;q.push(S),vis[S]=1,dis[S]=0; 18 while(!q.empty()){ 19 int top=q.front();q.pop();vis[top]=0; 20 for(int i=hd[top];i!=-1;i=nxt[i]) 21 if(dis[to[i]]>dis[top]+w[i]&&fl[i]){ 22 from[to[i]]=i; 23 dis[to[i]]=dis[top]+w[i]; 24 Min[to[i]]=min(Min[top],fl[i]); 25 if(!vis[to[i]]) 26 vis[to[i]]=1,q.push(to[i]); 27 } 28 } 29 return dis[T]!=inf; 30 } 31 32 inline int find(void){ 33 for(int i=T;i!=S;i=to[from[i]^1]) 34 fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T]; 35 return dis[T]*Min[T]; 36 } 37 38 inline int mcmf(void){ 39 int res=0; 40 while(spfa()) 41 res+=find(); 42 return res; 43 } 44 45 inline void add(int l,int s,int x,int y){ 46 w[cnt]=l;fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++; 47 w[cnt]=-l;fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++; 48 } 49 50 signed main(void){ 51 memset(hd,-1,sizeof(hd));S=0; 52 scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&fa,&fb);T=2*n+1; 53 for(int i=1,x;i<=n;i++){ 54 scanf("%d",&x),add(0,x,S,i),add(0,x,i+n,T); 55 if(i<n) 56 add(0,inf,i+n,i+n+1); 57 int lala=i+a+1,lalala=i+b+1; 58 if(lala<=n) 59 add(fa,inf,i,lala+n); 60 if(lalala<=n) 61 add(fb,inf,i,lalala+n); 62 }add(f,inf,S,1+n); 63 printf("%d\n",mcmf()); 64 return 0; 65 }//Cap ou pas cap. Pas cap. 66
By NeighThorn
BZOJ 3280: 小R的烦恼 & BZOJ 1221: [HNOI2001] 软件开发