https://ac.nowcoder.com/acm/contest/5666/H
题意:给一个带费用网络,q次询问,每次询问限定每条边的容量都为
u
/
v
u/v
u/v,问把单位1流量从1运输到n的最小费用。
题解:边容量
u
/
v
u/v
u/v,运输1,等价于边容量
u
/
v
∗
(
v
/
u
)
=
1
u/v*(v/u)=1
u/v∗(v/u)=1,运输
1
∗
(
v
/
u
)
=
v
/
u
1*(v/u)=v/u
1∗(v/u)=v/u,最后费用乘以
u
/
v
u/v
u/v即可。
比赛时想每条边容量一样,没必要网络流,直接最短路,依次求最短路然后删掉路径,直到不能连通
1
−
n
1-n
1−n,这样做是有问题的。比如如图,如果第一次最短路求了中间那条,后面就错了,但是用网络流有反向弧,还可以回退。
贪心,优先走费用小的路径,每次增广保存下来就行了,最多就增广
m
m
m次。
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 55
#define INF 0x3f3f3f3f
#define P pair<int,int>
#define MP(a,b) make_pair(a,b)
#define ll long long
int n,m,q,tot;
ll A,B;
ll sum[maxn];
struct Edge{
int from,to,cap,flow,cost;
};
struct MCMF{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[maxn];
int inq[maxn];
ll d[maxn];
int p[maxn];
int a[maxn];
void init()
{
edges.clear();
for(int i=1;i<=n;i++)G[i].clear();
int x,a,b,c,m0;
s=1,t=n;
cin>>m0;
while(m0--)
{
cin>>a>>b>>c;
AddEdge(a,b,1,c);
}
}
void AddEdge(int from,int to,int cap,int cost)
{
edges.push_back((Edge){from,to,cap,0,cost});
edges.push_back((Edge){to,from,0,0,-cost});
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BellmanFord(ll& flow,ll& cost)
{
for(int i=s;i<=t;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& e=edges[G[u][i]];
if(e.cap>e.flow && d[e.to]>d[u]+e.cost)
{
d[e.to]=d[u]+e.cost;
p[e.to]=G[u][i];
a[e.to]=min(a[u],e.cap-e.flow);
if(inq[e.to]==0){inq[e.to]=1;Q.push(e.to);}
}
}
}
if(d[t]==INF)return false;
flow+=a[t];
cost+=a[t]*d[t];
int u=t;
while(u!=s)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
u=edges[p[u]].from;
}
return true;
}
ll Mincost()
{
ll flow=0,cost=0;
while(BellmanFord(flow,cost))sum[flow]=cost,tot++;
return cost;
}
}ans;
int main()
{
//freopen("input.in","r",stdin);
while(cin>>n)
{
ans.n=n;
tot=0;
ans.init();
ans.Mincost();
cin>>q;
while(q--)
{
scanf("%lld%lld",&A,&B);
if(B>tot*A){puts("NaN");continue;}
ll qian=B/A;
if(qian*A>B)qian--;
if((qian+1)*A<=B)qian++;
ll mu=sum[qian]*A+(qian==tot?0:(sum[qian+1]-sum[qian])*(B-qian*A));
ll g=__gcd(mu,B);
printf("%lld/%lld\n",mu/g,B/g);
}
}
return 0;
}