题目大意:给出一张有向图n个点,m条边,每条边花费wi,有 q 次询问,给出一个 u 和 v ,将所有边的流量都设置为 u / v 后,从点 1 到点 n 流量为 1 时的最小花费为多少
题目思路:
我们首先建图然后跑一遍最小费用最大流,求出每一条从1到n路径的费用,并用数组记录(根据题目已知每个路径的流量都为1)我们假设从1到n总的流量为sum,接下来我们考虑每个询问
因为要求u/v*sum>=1,而如果u * sum<v的话,则输出NaN,因为我们有sum条路,如果每条都有流量也无法满足需求,否则的话,我们不断地加入每一条路径,并且累加费用,直到流量等于v时跳出循环,最后总的费用输出时分子分母同时除以分子分母的GCD即可
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1000 + 10;
struct edge
{
int u,v,c,f,cost;
edge(int u,int v,int c,int f,int cost):u(u),v(v),c(c),f(f),cost(cost){}
};
vector<edge>e;
vector<int>G[maxn];
int a[maxn],p[maxn],d[maxn],inq[maxn];
int n,m,cur;
ll cc[maxn],ff[maxn];
void init(int n)
{
cur=0;
for(int i=0;i<=n;i++)G[i].clear();
e.clear();
}
void addedge(int u,int v,int c,int cost)
{
e.push_back(edge(u, v, c, 0, cost));
e.push_back(edge(v, u, 0, 0, -cost));
int m=e.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}
bool bellman(int s, int t, int& flow, long long & cost)
{
for(int i=0;i<=n+1;i++)d[i] = INF;
memset(inq,0,sizeof(inq));
d[s]=0;inq[s]=1;
p[s]=0;a[s]=INF;
queue<int>q;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
inq[u]=0;
for(int i=0;i<G[u].size();i++){
edge&now=e[G[u][i]];
int v=now.v;
if(now.c>now.f&&d[v]>d[u]+now.cost){
d[v]=d[u]+now.cost;
p[v]=G[u][i];
a[v]=min(a[u], now.c - now.f);
if(!inq[v]){q.push(v);inq[v] = 1;}
}
}
}
if(d[t]==INF)return false;
flow+=a[t];
cost+=(long long)d[t] * (long long)a[t];
cc[++cur]=(long long)d[t]*(long long)a[t];
ff[cur]=a[t];
for(int u=t;u!=s;u=e[p[u]].u){
e[p[u]].f += a[t];
e[p[u]^ 1].f-=a[t];
}
return true;
}
int MincostMaxflow(int s, int t, long long & cost)
{
cost = 0;
int flow = 0;
while(bellman(s, t, flow, cost));
return flow;
}
int x,y,z,f,q;
int main()
{
ll mxflow,mincost;
while(~scanf("%d%d%",&n,&m)){
init(n);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&f);
addedge(x,y,1,f);
}
ll mxflow=MincostMaxflow(1,n,mincost);
scanf("%d",&q);
while(q--){
ll u,v;
scanf("%lld%lld",&u,&v);
if(u*mxflow<v) cout<<"NaN"<<endl;
else{
ll sum=0,cost=0;
for(int i=1;i<=cur;i++){
if(u+sum<v){
sum+=ff[i]*u;
cost+=cc[i]*u;
}
else{
cost+=cc[i]*(v-sum);
break;
}
}
ll k=__gcd(cost,v);
printf("%lld/%lld\n",cost/k,v/k);
}
}
}
return 0;
}