牛客多校1.H.Minimum-cost Flow

牛客多校1.H.Minimum-cost Flow

前话:因为多组没有初始化 c n t cnt cnt边的数量,导致一直超时,懵逼了,对于多组数据重建图时,只需要初始化 c n t cnt cnt h [ ] h[] h[]数组 ( h e a d [ ] ) (head[]) (head[])即可。

题意:给定 ( n , m ) (n,m) (n,m)无向图, m m m条带权有向边(费用已知容量未知),给 q q q次询问,每次询问给出 u , v , ( u ≤ v ) u,v,(u\leq v) u,v,(uv),问在所有边容量为 u v \dfrac{u}{v} vu下,总流量为 1 1 1的最小费用。

思路: M C M F + MCMF+ MCMF+贪心。

c o s t ( x , y ) 为 cost(x,y)为 cost(x,y)在所有边容量为 x x x下,总流量为 y y y的最小费用。

考虑先跑一边 M C M F MCMF MCMF,求出在所有边容量为 1 1 1下的所有增广路。

则题意变为求 c o s t ( u v , 1 ) cost(\dfrac{u}{v},1) cost(vu,1)

因为所有边容量一样,所以 c o s t = ∑ 增 广 路 个 数 c n t c n t f l o w [ e n d ] × d i s [ e n d ] = c a p a c i t y × ∑ 增 广 路 个 数 c n t c n t d i s [ e n d ] cost=\sum\limits_{增广路个数cnt}^{cnt} flow[end]\times dis[end]=capacity\times\sum\limits_{增广路个数cnt}^{cnt}dis[end] cost=广cntcntflow[end]×dis[end]=capacity×广cntcntdis[end]

c o s t cost cost c a p a c i t y capacity capacity成线性关系。

所以有 c o s t ( u v , 1 ) = c o s t ( u , v ) v cost(\dfrac{u}{v},1)=\dfrac{cost(u,v)}{v} cost(vu,1)=vcost(u,v)

且设 c a p a c i t y = 1 capacity=1 capacity=1对应的最大流为 m a x f l o w maxflow maxflow

c a p a c t i y = u capactiy=u capactiy=u对应的最大流也是线性关系为 m a x f l o w × u maxflow\times u maxflow×u

所以我们先考虑特判不成立的情况。

1 : v = 0 1:v=0 1:v=0,分母显然不能为0.

2 : m a x f l o w × u < v 2:maxflow\times u2:maxflow×u<v,表示能到达的最大流不能满足总流量为 v v v

接下我们考虑怎么构造答案。

我们需要构造出一个总流量为 v v v的方案,而每条增广路的流量贡献为 u u u

所以我们设 v = a × u + b v=a\times u+b v=a×u+b

表示我们需要 a a a条增广路和一条流量只需要 b b b的增广路。

之前我们已经求出了 c o s t ( 1 , m a x f l o w ) cost(1,maxflow) cost(1,maxflow)的所有增广路,因为 M C M F MCMF MCMF求增广路的顺序就是由最小费用到最大费用的,所以我们直接根据贪心思想取前 a a a条,和第 a + 1 a+1 a+1条作为 b b b

这样 c o s t ( u , v ) = a × ∑ i = 1 a a u g [ i ] + b × a u g [ a + 1 ] cost(u,v)=a\times \sum_{i=1}^a aug[i]+b\times aug[a+1] cost(u,v)=a×i=1aaug[i]+b×aug[a+1]

a u g [ i ] aug[i] aug[i]表示第 i i i条增广路的费用。

则最终答案为: c o s t ( u , v ) v \dfrac{cost(u,v)}{v} vcost(u,v),约分一下即可。

#include
using namespace std;
typedef long long ll;
const int N=105,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define fmst(a) memset(a,0x7f,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first
#define se second
#define pb push_back
int cnt=1,h[N],flow[N],dis[N],vis[N],n,m,s,t,ans[N],tot;
queue<int>q;
struct edge{
    int to,nt,f,w;//f:flow ,w:cost
}e[N<<1];
int pre[N];
void add(int u,int v,int f,int w){
    e[++cnt]={v,h[u],f,w},h[u]=cnt;
}
bool spfa(){// 跑spfa
    fmst(dis),fmst(flow),mst(vis);  //初始化.
    q.push(s),dis[s]=0,vis[s]=1,pre[t]=-1;//预处理
    while(!q.empty()){
        int u=q.front();q.pop();vis[u]=0;
        for(int i=h[u];i;i=e[i].nt){
            int v=e[i].to,f=e[i].f,w=e[i].w;
            if(f>0&&dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                pre[v]=i;
                flow[v]=min(flow[u],f);
                if(!vis[v]) vis[v]=1,q.push(v);
            }
        }
    }
    return pre[t]!=-1;
}
void MCMF(){    //MIncost Maxflow
    while(spfa()){
        int u=t,x=flow[t];
        ans[++tot]=dis[u];
        while(u!=s){
            e[pre[u]].f-=x;
            e[pre[u]^1].f+=x;
            u=e[pre[u]^1].to;
        }
    }
    for(int i=1;i<tot;i++) ans[i+1]+=ans[i];
}
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}
int main(){
    while(~scanf("%d%d",&n,&m)){
    s=1,t=n,tot=0,cnt=1;
    mst(h);
    for(int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,1,w),add(v,u,0,-w);
    }
    MCMF();
    int q;
    scanf("%d",&q);
    while(q--){
        int u,v;
        scanf("%d%d",&u,&v);
        if((!v)||1LL*tot*u<v) puts("NaN");
        else {
            int a=v/u,b=v%u;
            ll fz=1LL*ans[a]*u+1LL*b*(ans[a+1]-ans[a]);
            ll g=gcd(fz,v);
            printf("%lld/%lld\n",fz/g,v/g);
        }
    }
    }
    return 0;
}

你可能感兴趣的:(网络流)