*Minimum-cost Flow【网络流】

题意:

给出一个 (n) 点,(m) 条边有向图,点 (a_i)(b_i) 的花费为 (c_i),并且每条边的容量限制相同。(q) 次询问,每次给出两个数 (u_i)(v_i) ,每条边的容量限制为 (frac{u_i}{v_i}),每从 (1) 号点运送 (1) 个单位的物品,如果能够全部送达 (n),求出最小花费。否则,输出 ('NaN')

分析:

(x) 个单位的物品通过 (y) 的限制的通道从 (1) 运到 (n) 的花费记作:(cost(x,y))。那么要求 (cost(1,frac{u_i}{v_i})=cost(frac{v_i}{u_i},1)*frac{u_i}{v_i})。当每条边的容量固定为 (1) 时,可以直接用最小费用最大流求出每一条增广路径的花费,而且花费越小的增广路越先被走。当求出总的路径条数 (tol) ,即此时的最大流量。用 (tol*frac{u_i}{v_i} geq 1),判断是否可以满足要求。当满足要求时,为了最小费用,肯定按路径从小到大走。对于此时要求的流量 (frac{v_i}{u_i}),将其分配到路径中,求出花费,然后乘 (frac{u_i}{v_i}) 即可。
https://ac.nowcoder.com/acm/contest/5666/H

代码:

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int N=55;
const int inf=0x3f3f3f3f;
int ec[N<<1];//存每条增广路的花费
int flow[N],n,dis[N];
bool vis[N];
struct Node
{
    int to,val,cost,rev;
};
vector<Node>pic[N];
queue<int>que;
pii pre[N];//存上一个点
void add(int u,int v,int w,int c)
{
    pic[u].pb({v,w,c,pic[v].size()});
    pic[v].pb({u,0,-c,pic[u].size()-1});
}
bool spfa()
{
    while(!que.empty())
        que.pop();
    for(int i=1;i<=n;i++)
    {
        dis[i]=inf;
        flow[i]=inf;//存增广路的最小流量
        vis[i]=false;
    }
    dis[1]=0;
    vis[1]=true;
    que.push(1);
    while(!que.empty())
    {
        int now=que.front();
        que.pop();
        vis[now]=false;
        for(int i=0;i<pic[now].size();i++)
        {
            Node tmp=pic[now][i];
            if(dis[tmp.to]>dis[now]+tmp.cost&&tmp.val>0)
            {
                dis[tmp.to]=dis[now]+tmp.cost;
                vis[tmp.to]=true;
                flow[tmp.to]=min(flow[now],tmp.val);
                pre[tmp.to]=make_pair(now,i);
                que.push(tmp.to);
            }
        }
    }
    return dis[n]<inf;
}
void EK(int &tol)
{
    tol=0;
    while(spfa())
    {
        int mf=flow[n];
        for(int i=n;i!=1;i=pre[i].first)
        {
            pii d=pre[i];
            pic[d.first][d.second].val-=mf;
            pic[i][pic[d.first][d.second].rev].val+=mf;
        }
        tol++;
        ec[tol]=ec[tol-1]+mf*dis[n];//前缀和
    }
}
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    int m,a,b,c,q,u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int tol=0;
        for(int i=1;i<=n;i++)
            pic[i].clear();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,1,c);//转化为边的容量为1
        }
        EK(tol);
        scanf("%d",&q);
        while(q--)
        {
            ll ans=-1,g=1;
            scanf("%d%d",&u,&v);
            if(1LL*tol*u>=v)
            {
                int d=v/u,r=v%u;
                if(d+(r>0)<=tol)
                {
                    ans=1LL*ec[d]*u;
                    if(r>0)
                        ans=ans+1LL*(ec[d+1]-ec[d])*r;
                    g=gcd(ans,1LL*v);
                }
            }
            if(ans==-1) printf("NaN
");
            else printf("%lld/%lld
",ans/g,v/g);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/1024-xzx/p/13300229.html