CF1307G-解题报告

最小费用流与线性规划

最小费用流问题可以考虑看成一个线性规划问题。

fuv 为边的流量,cu,v 表示边的容量,wu,v 表示边的代价。V 表示点集,E 表示边集,记总的流量为 F

那么最小费用流问题等价于:

  • min{fu,vwu,v}
  • 限制:
    • 对所有 uV,有:

      (v,u)Efv,u(u,v)Efu,v={F,if u=nF,if u=10,otherwise

    • 对所有 (u,v)E,有 0fu,vcu,v
  • m 个变量 fu,vn+m 条限制。

给出线性规划一般形式和其对偶问题:

原问题:

maxz=j=1mcjxjAxbx0

对偶问题:

minw=j=1nbjyjATycy0

这里 A,x,b,c,y 均为矩阵,其中 An×m 矩阵,x,cn×1 矩阵,y,bm×1 矩阵。定义矩阵之间的 为对应位置都需要小于。

不加证明的给出以下定理:

  • 线性规划和其对偶线性规划等价。

这里不给证明的原因是该定理证明较为繁杂,博主不会证明,且本博客内容与该性质内容关系不大。

把最小费用流问题对应线性规划的限制转化成一般形式:

{+fv,ufu,vaifu,v+fu,vaifu,vcu,v

其中 au 表示点 u 应该的流量: F,F0

把这个线性规划的对偶形式写出来,限制一共有 2n+m 个,考虑前 n 个限制代表变量为 qi,另外 n 个限制代表变量为 ei,后 m 个限制设为 ru,v

考虑前 2n 个向量与限制的对应关系,对于一个限制来说,显然我们可以让 qu 来对应 +fv,ufu,vai,这样所有 fv,u 代表的位置会有 +qufv,u 代表的位置会有 qu。强烈建议各位读者画一个矩阵自己感受一下。

最后化成对偶线性规划为:

  • max{auqu aueuru,vwu,v}
  • 限制:
    • 对于所有 (u,v)E,有:qu+qv+euevru,vwu,v
    • qu,eu,ru,v0
  • 一共 m 条限制。

需要注意在推式子的时候,特别关注一下无入度点和无出度点的的情况,它们也是满足条件的。

发现所有式子都与 queu 有关,不如设其为 du。以及注意到 au 除了 1,n 都是 0,所以线性规划变成:

  • max{F(dnd1)ru,vcu,v}
  • 限制:
    • 对于所有 (u,v)E,有:dvdu+ru,v+wu,v
    • du,ru,v0
  • 一共 m 条限制。

du 依然满足 0 的原因是,考虑如果找到了一组满足条件的 d,那么把 d 同加到 0 依然满足条件。

Solution

题目大意:给定 n 个点 m 条边的有向图,边权为 w,可以选择把一条边的边权 wi 修改为 wi+aiai 可以为实数,但是需要满足 ai0,aix,有 q 次询问,每次给定 x,询问修改之后 1n 最短路的最大值,每次询问独立,无重边无自环。n50,wi106,w105

关注我们的对偶问题,发现限制如同最短路,而 ru,v 就像我们给每条边加上的权值 ai

关注我们对偶线性规划求的东西,可以令 cu,v=1,那么现在变成了求 max{F(dnd1)ru,v},其中后者相当于我们更改的权值总和,设为 C,同时记 D=dnd1 设为最短路。

我们把所有有用的 (C,D) 映射到二维平面上,形成的图形一定是上凸壳,且斜率最大是 1。并且,凸壳上的拐点一定都是整点。且如果让 ai 都是整数,那么显然随着 C 的增加,D 要么不变,要么加一,在这个情况下建立凸包,而考虑如果令 ai 可以为实数,不难发现凸包不会变化。如图:

如果令所有 ai 都是整数,那么点应该是 E,F,G,而如果 ai 可以为实数,那么点 I,J,K

由此可以得出结论,凸包上的所有切线都形如 1x 的形式,其中 x 是整数。

A(F)=maxD,C{FDC},设对于给定 F,有 A(F)=FDFCF,那么 DF=A(F)F+CFF。由此可知,若给定 FA(F),方法即为用 1F 去切这个凸包,而切线与 x 轴的截距为 A(F)

原问题等价于给定 C,要求在凸包上找到 x=C 与凸壳的交点 (C,D)。考虑所有的 F 和它们对应的切线在 x=C 处的值,设为 y,不难发现有 yD,且一定存在一个 x,使得 y=D,即一条与凸包相切且切点为 (C,D) 的切线。则答案为 minF{A(F)F+CF}

现在唯一的问题是 F 是可以为实数的,一个方法是可以二分,不过不用这么麻烦。我们其实只用考虑 F 是整数的情况,这是因为凸包上所有的斜率都形如 1x,所有对于凸包上每个点 (C,D),都存在一个整数 F 使得斜率为 1F 的切线经过这个点。

所以,我们枚举 F,通过费用流算出 A(F),对于每个询问,算出 minF{A(F)F+CF} 即可。

代码

int n,m;

struct edge{
    int to,next,w,f;
    inline void Init(int to_,int ne_,int w_,int f_){
        to=to_;next=ne_;w=w_;f=f_;
    }
}li[N*N*2];
int head[N],tail=1,now[N],d[N],s,t,Ans,A[N],ans,Q;
bool vis[N];
queue<int> q;

inline void Add(int from,int to,int w,int f){
    li[++tail].Init(to,head[from],w,f);head[from]=tail;swap(from,to);
    li[++tail].Init(to,head[from],-w,0);head[from]=tail;
}
inline bool spfa(int s){
    while(q.size()) q.pop();
    bool op=0;
    mset(d,INF);mset(vis,0);d[s]=0;q.push(s);vis[s]=1;now[s]=head[s];
    while(q.size()){
        int top=q.front();q.pop();vis[top]=0;
        Next(top){
            int to=li[x].to,f=li[x].f,w=li[x].w;if(!f||d[to]<=d[top]+w)continue;
            d[to]=d[top]+w;if(!vis[to]) vis[to]=1,q.push(to);now[to]=head[to];
        }
    }
    if(d[t]>=INF) return 0;else return 1;
}
inline int dinic(int k,int flow){
    if(k==t) return flow;int rest=flow,x;vis[k]=1;
    for(x=now[k];x&&rest;x=li[x].next){
        int to=li[x].to,f=li[x].f,w=li[x].w;
        if(!f||d[to]!=d[k]+w||(vis[to]&&to!=t)) continue;int val=dinic(to,min(rest,f));
        if(!val) d[to]=INF;li[x].f-=val;li[x^1].f+=val;rest-=val;Ans+=val*w;
    }
    now[k]=x;
    return flow-rest;
}

signed main(){
    // freopen("my.in","r",stdin);
    // freopen("my.out","w",stdout);
    read(n);read(m);
    rep(i,1,m){
        int from,to;read(from);read(to);int w;read(w);
        Add(from,to,w,1);
    }
    s=1,t=n;
    rep(i,1,n){
        if(!spfa(s)) break;
        ans+=dinic(s,1);
        A[i]=Ans;
    }
    read(Q);
    rep(i,1,Q){
        int x;read(x);
        ld nowans=INF;
        rep(i,1,n){
            if(!A[i]) break;
            cmin(nowans,(ld)(A[i]+x)/(ld)(i));
        }
        printf("%0.7Lf\n",nowans);
    }
    return 0;
}
posted @   NuclearReactor  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
主题色彩