【网络流/牛客第一场H】Minimum-cost Flow

链接:https://ac.nowcoder.com/acm/contest/5666/H
来源:牛客网
 

题目描述

Bobo has a network of n nodes and m arcs. The i-th arc goes from the ai​-th node to the bi-th node, with cost ci​.

Bobo also asks q questions. The iii-th question is specified by two integers ui and vi​, which is to ask the minimum cost to send one unit of flow from the 1-th node to the n-th node, when all the edges have capacity ui/vi(a fraction).

You can refer the wiki page for further information of Minimum-cost Flow.

输入描述:

The input consists of several test cases terminated by end-of-file.

The first line of each test case contains two integers n and m. The i-th of the following m lines contains three integers ai, bi​ and ci​. The next line contains an integer q. The i-th of the last q lines contains two integers ui​ and vi​.

* 2≤n≤50
* 1≤m≤100
* 1≤ai,bi≤n
* 1≤ci≤1e5
* 1≤q≤1e5
* 0≤ui≤vi≤1e9
* The sum of m does not exceed 1e4.
* The sum of q does not exceed 1e6.

输出描述:

For each test case, print q fractions (or `NaN`, if it is impossible to send one unit of flow) which denote the answer.

示例1

输入

2 1
1 2 2
1
1 1
2 2
1 2 1
1 2 2
3
1 2
2 3
1 4

输出

2/1
3/2
4/3
NaN

 

思路:多个询问,每次询问当每条路的最大流量为u/v时的最小花费。

可以将图放大u倍,即每条路的容量为u,最大流量为v是的最小花费为c,则实际答案为c/v。

实现时可以先预处理出每增加一点流量所增加的最小花费和最大流量。容量为u时扩大u倍。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

const int N = 55,M = 205;
int n,m;
int first[N],ne[M],e[M],flow[M],cost[M],num_edge=0;
int dist[N];
bool vis[N];
int cnt=0,f[M];
ll t,add_cost[M],precost;
void add(int x,int y,int f,int c){
    ne[num_edge]=first[x];
    e[num_edge]=y;
    flow[num_edge]=f;
    cost[num_edge]=c;
    first[x]=num_edge++;
}
bool spfa(){
    memset(dist,inf,sizeof(dist));
    memset(vis,false,sizeof(vis));
    queue<int>q;
    q.push(1),dist[1]=0,vis[1]=true;
    int x,y;
    while(!q.empty()){
        x=q.front(),q.pop(),vis[x]=false;
        for(int i = first[x]; i!=-1; i=ne[i]){
            y=e[i];
            if(dist[y]>dist[x]+cost[i]&&flow[i]>0){
                dist[y]=dist[x]+cost[i];
                if(!vis[y])q.push(y),vis[y]=true;
            }
        }
    }
    return dist[n]!=inf;
}
int dfs(int x,int y){
    if(x==n)return y;
    int u,k=y,d;
    vis[x]=true;
    for(int i = first[x];i!=-1&&k>0;i=ne[i]){
        u=e[i];
        if(dist[u]==dist[x]+cost[i]&&flow[i]&&!vis[u]){
            d=dfs(u,min(k,flow[i]));
            if(d==0)dist[u]=inf;
            k-=d;
            flow[i]-=d,flow[i^1]+=d;
            t+=d*cost[i];
        }
    }
    vis[x]=false;
    return y-k;
}
void solve(ll u,ll v){
    ll cc=0,flow=v;
    for(int i = 1; i <= cnt;i++){
        if(u*(ll)f[i]<=flow){
            cc+=(ll)add_cost[i]*u*f[i];
            flow-=u*(ll)f[i];
        }
        else{
            cc+=(ll)add_cost[i]*flow;
            flow=0;
            break;
        }
    }
    if(flow)printf("NaN\n");
    else{
        ll k = __gcd(cc,v);
        //printf("%lld\n",v);
        printf("%lld\/%lld\n",cc/k,v/k);
    }
}
int main(){
    int a,b,c,qq;
    ll u,v;
    while(~scanf("%d%d",&n,&m)){
        memset(first,-1,sizeof(first));
        num_edge=0,cnt=0,t=0;
        for(int i = 1; i <= m; i++){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,1,c),add(b,a,0,-c);
        }
        precost=0,t=0;
        while(spfa()){

            memset(vis,false,sizeof(vis));
            f[++cnt]=dfs(1,1);
            add_cost[cnt]=t-precost;
            precost=t;
        }
        //for(int i = 1; i <= cnt; i++)printf("kkkk%d %d\n",i,add_cost[i]);
        scanf("%d",&qq);
        while(qq--){
            scanf("%lld%lld",&u,&v);
            solve(u,v);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值