zoukankan      html  css  js  c++  java
  • 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

    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.

     
    题解:
    先要将每一天拆成两个点分别表示这天开始和结束
    由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
    ",f.totcost);
    72         else puts("impossible");
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    bzoj2733 永无乡 平衡树按秩合并
    bzoj2752 高速公路 线段树
    bzoj1052 覆盖问题 二分答案 dfs
    bzoj1584 打扫卫生 dp
    bzoj1854 游戏 二分图
    bzoj3316 JC loves Mkk 二分答案 单调队列
    bzoj3643 Phi的反函数 数学 搜索
    有一种恐怖,叫大爆搜
    BZOJ3566 概率充电器 概率dp
    一些奇奇怪怪的过题思路
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/5152605.html
Copyright © 2011-2022 走看看