bzoj 3280: 小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”。注意,由于程设老师良心大大的坏,所以他是可以不把濒死的研究生送去医院的!

题解:

但愿我将来能不会遇到这种程设老师

这道题不就是餐巾(网络流24题)吗...

建模如下:
1055088-20170317212635495-2079612027.png

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
    x=0;char ch;bool flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 40010;
const int maxnode = 40010;
const int inf = 0x3f3f3f3f;
struct Edge{
    int to,next,cap,cost;
}G[maxnode<<1];
int head[maxnode],cnt=1;
void add(int u,int v,int c,int d){
    G[++cnt].to = v;
    G[cnt].next = head[u];
    head[u] = cnt;
    G[cnt].cap = c;
    G[cnt].cost = d;
}
inline void insert(int u,int v,int c,int d){
    add(u,v,c,d);add(v,u,0,-d);
}
#define v G[i].to
const int lim = maxnode<<1;
int dis[maxnode],flow[maxnode],p[maxnode],q[lim+10];
int S,T,l,r,ans,tot_flow;bool inq[maxnode];
inline bool spfa(){
    memset(dis,0x3f,sizeof dis);
    inq[S] = true;dis[S] = 0;
    flow[S] = inf;l = 0;r = -1;
    q[++r] = S;
    while(l <= r){
        int u = q[l % lim];++l;
        for(int i = head[u];i;i=G[i].next){
            if(dis[v] > dis[u] + G[i].cost && G[i].cap){
                dis[v] = dis[u] + G[i].cost;
                flow[v] =  min(flow[u],G[i].cap);
                p[v] = i;
                if(!inq[v]){
                    q[++r % lim] = v;
                    inq[v] = true;
                }
            }
        }inq[u] = false;
    }if(dis[T] == dis[T+1]) return false;
    ans += dis[T]*flow[T];
    tot_flow += flow[T];
    for(int u = T;u != S;u = G[p[u]^1].to)
        G[p[u]].cap -= flow[T],G[p[u]^1].cap += flow[T];
    return true;
}
#undef v
int a[maxn],L[maxn],P[maxn],D[maxn],Q[maxn];
inline void init(){
    memset(head,0,sizeof head);
    cnt = 1;tot_flow = 0;ans = 0;
}
inline void work(){
    init(); 
    int n,m,k;read(n);read(m);read(k);
    S = maxnode - 5;T = S + 1;
    for(int i=1;i<=n;++i){
        read(a[i]);tot_flow -= a[i];
        insert(i,T,a[i],0);
        insert(S,i+n,a[i],0);
        if(i != n) insert(i,i+1,inf,0);
    }
    for(int i=1;i<=m;++i){
        read(L[i]);read(P[i]);
        insert(S,1,L[i],P[i]);
    }
    for(int i=1;i<=k;++i){
        read(D[i]);read(Q[i]);
        for(int j=1;j<=n;++j){
            if(j + D[i] + 1 > n) break;
            insert(j+n,j+D[i]+1,inf,Q[i]);
        }
    }
    while(spfa());
    if(tot_flow < 0) puts("impossible");
    else printf("%d\n",ans);
}
int main(){
    int T;read(T);
    for(int i=1;i<=T;++i){
        printf("Case %d: ",i);
        work();
    }
    getchar();getchar();
    return 0;
}

转载于:https://www.cnblogs.com/Skyminer/p/6568424.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值