最小圈

3 篇文章 0 订阅
0 篇文章 0 订阅

Description

对于一张有向图, 求最小的圈平均值,即若一颗圈经过  k    k   个节点,那么一个圈的平均值为圈上  k    k   条边权的和除以  k   k ,现要求其中的最小值。

Input

第一行  2    2   个正整数,分别为  n    n    m   m
以下  m    m   行,每行  3    3   个数,表示边连接的信息

Output

一行一个数,表示最小圈的值。你的答案被视为正确当且仅当与标准答案的绝对误差不超过 1e5 1 e − 5

Data Constraint

20%n<=100,m<=1000 20 % : n <= 100 , m <= 1000
60%:n<=1000,m<=5000 60 % : n <= 1000 , m <= 5000
100%:n<=3000,m<=10000 100 % : n <= 3000 , m <= 10000
absWi,j<=105 a b s ( W i , j ) <= 10 5

Sample Input

输入1:
4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
输入2:
2 2
1 2 -2.9
2 1 -3.1

Sample Output

输出1:
3.666667
输出2:
-3.000000

Solution

二分答案,分数规划,将求值问题变成可行性判断问题。
然后要利用深搜版  SPFA    S P F A   或者  dfs   d f s ,用于判负环,来求可行性,如果是宽搜的话会被  T   T
原理:
若事先把所有边加上或减去一个值,则相应地会增大或减少所有圈的平均值。假设存在一个  ans    a n s   待判断,那么我们把所有边减去  ans    a n s    spfa    s p f a   一下,当  dis>0    d i s > 0   时不再走下去。若最终找到一个负环,说明  ans    a n s   答案是可行的,修改上界,否则修改下界。而这最终结果是得到一个  ans   a n s ,然后  spfa    s p f a   得到一个  dis=0    d i s = 0   的环。

Code

const   maxn=3005;
        maxm=10005;
        e=0.000001;
var     tot,i,n,m:longint;
        l,r,mid:real;
                p:boolean;
        cost,w:array[1..maxm] of real;
        next,yy,u,v:array[1..maxm] of longint;
        g:array[1..maxn] of longint;
        dis:array[1..maxn] of real;
        vis:array[1..maxn] of boolean;
procedure make(x,y:longint;z:real);
begin
    inc(tot);
    yy[tot]:=y;
    cost[tot]:=z;
    next[tot]:=g[x];
    g[x]:=tot;
end;
procedure spfa(x:longint);
var     i,y:longint;
begin
    vis[x]:=true;
    i:=g[x];
    while i<>0 do begin
        y:=yy[i];
        if dis[x]+cost[i]<dis[y] then begin
            if vis[y] then begin
                p:=true;
                break;
            end;
            dis[y]:=dis[x]+cost[i];
            spfa(y);
            if p then break;
        end;
        i:=next[i];
    end;
    vis[x]:=false;
end;
function judge(x:real):boolean;
begin
    tot:=1;p:=false;
    fillchar(next,sizeof(next),0);
    fillchar(g,sizeof(g),0);
    fillchar(cost,sizeof(cost),0);
    fillchar(yy,sizeof(yy),0);
    fillchar(vis,sizeof(vis),false);
    fillchar(dis,sizeof(dis),0);
    for i:=1 to m do make(u[i],v[i] ,w[i]-x);
    for i:=1 to n do begin
        spfa(i);
        if p then exit(p);
    end;
    exit(false);
end;
begin
    readln(n,m);
    for i:=1 to m do readln(u[i],v[i],w[i]);
    l:=-100005;r:=100005;
    while l+e<r do begin
        mid:=(l+r)/2;
        if judge(mid) then r:=mid else l:=mid+e;
    end;
    writeln(l:0:6);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值