给定一张图,求最小费用流(源点流量为 1 1 1)
多个询问,每个询问将所有边的容量变为 u v \frac{u}{v} vu,求费用
首先我们考虑费用流,如果所有边容量相同,为 c a p cap cap。
那么如果源点流量够多,每次增广得到的改进量是不会变化的,恒为 c a p cap cap。
回过来考虑这道题:对于源点流量有限的情况,在前面够的时候为 c a p cap cap,不够的时候就是剩余的流量 f l o w flow flow。
对于某个询问,容量 c a p = u v cap=\frac{u}{v} cap=vu,流量为 1 1 1。
我们将流量和容量都扩大 v v v倍,流量为 v v v,容量为 u u u,显然最后的花费也会被扩大 v v v倍(因为整张图没有发生实际的变化,所以费用流的实际过程并没有变化)
这个时候我们每次增广 u u u,直到不够为止,就可以得到结果。
具体做法为:
1、令容量为 1 1 1,求出单位情况下费用流的过程,记录下每次增广花费的费用。(这里我们直接建图,相当于源点的流量是无穷多的)
2、实际询问的时候就是在已知整个过程的基础上,每次增广 u u u,剩下流量就为 v − u v-u v−u,然后继续增广,直到没有为止。(记录的时候是无穷多流量,但实际询问的时候流量只有 v v v)
3、如果最后流量仍然还剩,等于告诉你,无穷多流量都已经没得跑了,这里的 v v v多的等于是无穷多了,也就是你跑不满最大流了,输出错误。
#include
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 500;
const int mod = 1e9 + 7;
const ll inf = 1e18;
struct Edge{
int from,to;
ll cap,flow,cost;
};
vector<ll>mp;
struct MCMF{
int n,tmp,s,t;
vector<Edge>edges;
vector<int>G[maxn];
int inq[maxn];
ll d[maxn];//spfa
int p[maxn];//上一条弧便于回溯
ll a[maxn];//最小改进量
void init(int n,int s,int t){
this->n=n,this->s=s,this->t=t;
edges.clear();
for(int i=1;i<=n;i++)G[i].clear();
}
void AddEdge(int from,int to,ll cap,ll cost){
edges.push_back((Edge){from,to,cap,0,cost});
edges.push_back((Edge){to,from,0,0,-cost});
tmp=edges.size();
G[from].push_back(tmp-2);
G[to].push_back(tmp-1);
}
bool spfa(int s,int t,ll& flow,ll& cost){
for(int i=0;i<=n;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]){Q.push(e.to);inq[e.to]=1;}//入队
}
}
}
if(d[t]==inf)return false;//说明不连通了。
flow+=a[t];//如果固定流量的话,可以在flow+a>=k的时候只增广到k,然后终止程序
cost+=d[t]*a[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(spfa(s,t,flow,cost)){
mp.push_back(d[t]);
}
return flow;
}
}mf;
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
mp.clear();
mf.init(n,1,n);
for(int i=1;i<=m;i++){
int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);
mf.AddEdge(u,v,1,w);
}
mf.Mincost();
int q;scanf("%d",&q);
while(q--){
int u,v;scanf("%d%d",&u,&v);
ll ansu=0,ansv=v;
for(int i=0;i<mp.size();i++){
if(v>u){
v-=u;
ansu+=mp[i]*u;
}
else{
ansu+=mp[i]*v;
v=0;
}
}
if(v){
puts("NaN");
continue;
}
ll gcd=__gcd(ansu,ansv);
ansu/=gcd,ansv/=gcd;
printf("%lld/%lld\n",ansu,ansv);
}
}
}