[LP对偶费用流] JAG Practice Contest 2015 J Longest Shortest Path

一个有向图 起点为s 终点为t 每条边有个初始长度de和边权ce。
可以花x*ce的代价将一条边的长度增加x 但是不能减小。
问不超过P的代价最大化s到t的最短路

好题 就是不知道能不能直接线性规划艹过去
以下全部抄题解 balabala

现列出限制

这里写图片描述

然后对偶

这里写图片描述

这里写图片描述

发现这个是流量的形式

这里写图片描述

这里写图片描述

然后进行变量的变换

这里写图片描述

变成

这里写图片描述

由最小费用最大流的性质知 目标函数的一部分 g(m) 是下凸的

这里写图片描述

ans=g(m)/m
g(m)=ansm
相当于用过原点的直线去切这个函数 切点之一一定在顶点上 定点的横坐标一定是整数
那么就只要每次增广一次流更新下答案就好了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=205;
const int M=2005;

struct edge{
  int u,v,w,f; int next;
}G[M<<1];
int head[N],inum=1;
inline void add(int u,int v,int w,int f,int p){
  G[p].u=u; G[p].v=v; G[p].w=w; G[p].f=f; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int w,int f){
  add(u,v,w,f,++inum); add(v,u,-w,0,++inum);
}
#define oo 1<<29
int n,m,P;
int S,T,Mincost;
int Q[N*M],l,r;
int dis[N],pre[N],ins[N];
#define V G[p].v
inline bool SPFA(){
  for (int i=1;i<=n;i++) dis[i]=oo,pre[i]=0,ins[i]=0;
  l=r=-1; Q[++r]=S,dis[S]=0,ins[S]=1;
  while (l<r){
    int u=Q[++l]; ins[u]=0;
    for (int p=head[u];p;p=G[p].next)
      if (G[p].f && dis[V]>dis[u]+G[p].w){
    dis[V]=dis[u]+G[p].w; pre[V]=p;
    if (!ins[V]) Q[++r]=V,ins[V]=1;
      }
  }
  if (dis[T]==oo) return 0;
  Mincost+=dis[T];
  for (int p=pre[T];p;p=pre[G[p].u])
    G[p].f--,G[p^1].f++;
  return 1;
}

int main(){
  int u,v,c,d;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m); read(P); read(S); read(T);
  for (int i=1;i<=m;i++)
    read(u),read(v),read(d),read(c),link(u,v,d,c);
  double ans=1e20; int m=0;
  while (SPFA()){
    m++;
    ans=min(ans,(double)(Mincost+P)/m);
  }
  printf("%.10lf\n",ans);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值