c........x 4^8^2^6 ssl 2554 小澳的葫芦 01分数规划+最短路

Description

小澳最喜欢的歌曲就是《葫芦娃》。
一日表演唱歌,他尽了洪荒之力,唱响心中圣歌。
随之,小澳进入了葫芦世界。
葫芦世界有n个葫芦,标号为1~ n。n个葫芦由m条藤连接,每条藤连接了两个葫芦,这些藤构成了一张有向无环图。小澳爬过每条藤都会消耗一定的能量。
小澳站在1号葫芦上(你可以认为葫芦非常大,可以承受小澳的体重),他想沿着藤爬到n号葫芦上,其中每个葫芦只经过一次。
小澳找到一条路径,使得消耗的能量与经过的葫芦数的比值最小。

Input

输入文件名为calabash.in。
输入文件第一行两个正整数n,m,分别表示葫芦的个数和藤数。
接下来m行,每行三个正整数u,v,w,描述一条藤,表示这条藤由u连向v,小澳爬过这条藤需要消耗w点能量。

Output

输出文件名为calabash.out。
一行一个实数,表示答案(绝对误差不超过 10^-3)。

分析

先加入一个新点0,从0到1连一条长度为0的边,那么问题就穿换成了路径长度/边数最小。

设答案为ans,可得答案路径:

(w[1]+w[2]+w[3]...w[n])/n=ans

变式:
w[1]+w[2]+w[3]...w[n]=ansn

继续:
(w[1]ans)+(w[2]ans)+(w[3]ans)...(w[n]ans)=0

那么我们就二分一个答案ans,然后把每条边的权值减去ans,若1到n的最短路=0,则ans就是答案。
如果1到n的最短路>0,则l=mid+1
如果1到n的最短路<0,则r=mid-1
神tm的ssl的int64.。。

代码

const
  maxe=50000;
  maxv=3000000;

type
  arr=record
    x,y,next:longint;
    w:longint;
  end;

var
  n,m,s,q:longint;
  ls:array[0..maxe] of longint;
  a:array[0..maxv] of arr;
  f:array[0..maxe] of int64;
  v:array[0..maxe] of longint;
  d:array[0..maxv] of longint;
  i,j,k:longint;
  ans:int64;
  x,y:longint;
  l,r,mid:int64;
  max:int64;

function spfa(s,t:longint;mid:int64):int64;
var
  i,j,k:longint;
  head,tail:longint;
begin
  fillchar(f,sizeof(f),$7f);
  max:=f[1];
  head:=0;
  tail:=1;
  v[s]:=1;
  d[1]:=s;
  f[s]:=1;
  repeat
    head:=head+1;
    j:=ls[d[head]];
    while j<>0 do
      begin
        with a[j] do
          begin
            if f[x]+w-mid<f[y]
              then
                begin
                  f[y]:=f[x]+w-mid;
                  if v[y]=0
                    then
                      begin
                        tail:=tail+1;
                        d[tail]:=y;
                        v[y]:=1;
                      end;
                end;
            j:=next;
          end;
      end;
    v[d[head]]:=0;
  until head=tail;
  spfa:=f[t];
end;

begin
  readln(n,m);
  fillchar(ls,sizeof(ls),0);
  for i:=1 to m do
    begin
      with a[i] do
        begin
          readln(x,y,w);
          w:=w*10000;
          next:=ls[x];
          ls[x]:=i;
        end;
    end;
  m:=m+1;
  a[m].x:=0;
  a[m].y:=1;
  ls[0]:=m;
      ans:=0;
      x:=0; y:=n;
      l:=0; r:=200000000; mid:=0;
      while (l<r) do
        begin
          mid:=(l+r) div 2;
          if spfa(x,y,mid)>=0
            then begin
              ans:=mid;
              l:=mid+1;
            end
          else
            r:=mid-1;
        end;
      write(ans/10000:0:3);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值