[二分+有上下界最大流] ZOJ3496: Assignment

题意

Company A wants to transport as many goods as possible from city S to city T. So they ask company B to do the transportation. There are n cities here in the problem and there are directed roads from cities i to city j with capacity cij.

After a long negotiation, A and B reach a consensus that A first decide how to transport the goods (Of course under the condition that most goods are transported and that the quantity transported in each road cannot exceed the capacity) and then B can assign non-negative integer unit transportation costs to each road such that the total unit transportation costs in all roads sum to P. So the money A has to pay is the sum of costs of all roads while the cost of a certain road is the quantity transported (assigned by A) multiplied by the unit transportation cost (assigned by B). Notice that since the goods are not divisible, the quantity transported for each road should be a non-negative integer.

Of course A wants to minimize the cost and B want to maximize the cost. So you are to work out what the total cost will be?

To make the problem more fun, you should also work out the total cost that A wants to maximize the cost while B wants to minimize it and other conditions keep the same.
2 ≤ n ≤ 500, 0 ≤ m ≤ 10000, 0 ≤ S, T < n, 0 ≤ P ≤ 100000

题解

这题题目意思比较绕,看懂了就是大水题了。
实际上B公司设定边权时肯定是贪心的只在流量最大(小)的一条上加P,而A公司就是要使流量最大(小)的边的流量最小(大)。
所以二分答案,然后刷有上下界的最大流验证即可。

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
    char ch=gc(); int res=0,ff=1;
    while(!('0'<=ch&&ch<='9')){ if(ch=='-') ff=-1; ch=gc(); }
    while('0'<=ch&&ch<='9') res=(res<<3)+(res<<1)+ch-'0', ch=gc();
    return res*ff;
}
const int maxn=605, maxe=40005;
int n,m,S,T,SS,TT,P,_test,ans,MaxFlow;
struct Edge{
    int from,to,flow,cap;
    Edge(int t1=0,int t2=0,int t3=0,int t4=0){ from=t1; to=t2; flow=t3; cap=t4; }
} Es[maxe];

struct data{ int x,y,z; } a[maxe];
int fir[maxn],nxt[maxe],tot=1;
void add(int x,int y,int z){
    Es[++tot]=Edge(x,y,0,z); nxt[tot]=fir[x]; fir[x]=tot;
    Es[++tot]=Edge(y,x,0,0); nxt[tot]=fir[y]; fir[y]=tot;
}
queue< int > que;
int N,d[maxn],pos[maxn],tmp[maxn];
bool Bfs(int S,int T){
    memset(d,63,sizeof(d)); int INF=d[0];
    que.push(S); d[S]=0; 
    while(!que.empty()){
        int x=que.front(); que.pop();
        for(int j=fir[x];j;j=nxt[j]) if(d[Es[j].to]==INF&&Es[j].cap>Es[j].flow){
            d[Es[j].to]=d[x]+1; que.push(Es[j].to);
        }
    }
    return d[T]!=INF;
}
int find_Dfs(int x,int flow,int T){
    if(x==T||flow==0) return flow;
    int res=0,t;
    for(int &j=pos[x];j;j=nxt[j]){
        if(d[x]+1==d[Es[j].to]&&(t=find_Dfs(Es[j].to,min(flow,Es[j].cap-Es[j].flow),T))>0){
            Es[j].flow+=t; Es[j^1].flow-=t; 
            res+=t; flow-=t; if(flow==0) break;
        }
    }
    return res;
}
int Dinic(int S,int T){
    int res=0;
    while(Bfs(S,T)){
        for(int i=1;i<=N;i++) pos[i]=fir[i]; 
        res+=find_Dfs(S,1e+9,T);
    }
    return res;
}
void getMaxFlow(){
    memset(fir,0,sizeof fir); tot=1;
    for(int i=1;i<=m;i++) add(a[i].x,a[i].y,a[i].z);
    N=n; MaxFlow=Dinic(S,T);
}
void Del(int x){
    for(int j=fir[x];j;j=nxt[j]) Es[j].flow=Es[j].cap=Es[j^1].flow=Es[j^1].cap=0;
}
bool check(int _L,int _R){
    memset(fir,0,sizeof fir); tot=1;
    N=n; SS=++N; TT=++N;
    memset(tmp,0,sizeof tmp);
    for(int i=1;i<=m;i++){
        int fL=_L, fR=min(_R,a[i].z);
        if(fL>fR) continue;
        add(a[i].x,a[i].y,fR-fL); tmp[a[i].x]-=fL; tmp[a[i].y]+=fL;
    }
    int blc=0;
    for(int i=1;i<=n;i++){
        if(tmp[i]>0) add(SS,i,tmp[i]), blc+=tmp[i];
                else add(i,TT,-tmp[i]); 
    }
    add(T,S,1e+9);
    if(Dinic(SS,TT)<blc) return false;
    int res=Es[tot-1].flow;
    Es[tot].flow=Es[tot].cap=Es[tot-1].flow=Es[tot-1].cap=0; Del(SS); Del(TT);
    return res+Dinic(S,T)==MaxFlow;
}
int main(){
    freopen("zoj3496.in","r",stdin);
    freopen("zoj3496.out","w",stdout);
    _test=getint();
    while(_test--){
        n=getint(); m=getint(); S=getint()+1; T=getint()+1; P=getint();
        for(int i=1;i<=m;i++) a[i].x=getint()+1, a[i].y=getint()+1, a[i].z=getint();
        getMaxFlow();
        int L=0,R=1000000; ans=0;
        while(L<=R){
            int mid=(L+R)>>1;
            if(check(0,mid)) R=mid-1, ans=mid;
                        else L=mid+1;
        }
        printf("%lld ",((long long)ans)*P);
        L=0,R=1000000; ans=0;
        while(L<=R){
            int mid=(L+R)>>1;
            if(check(mid,1e+9)) L=mid+1, ans=mid;
                           else R=mid-1;
        }
        printf("%lld\n",((long long)ans)*P);
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值