链接: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);
}
}
}