[HNOI2009] 最小圈

题目描述:

求最小平均权值环

题目分析:

很明显是个分数规划的题目
ans=(ki=1w[i])/k a n s = ( ∑ i = 1 k w [ i ] ) / k
ansk=(ki=1w[i]) a n s ∗ k = ( ∑ i = 1 k w [ i ] )
(ki=1w[i])ansk=0 ( ∑ i = 1 k w [ i ] ) − a n s ∗ k = 0
如果我们能够在图中找到一个负环,就说明ans可以继续缩小
使用实数二分即可

题目链接:

Luogu 3199

Ac 代码:

// luogu-judger-enable-o2
#include <cstdio>
#include <iostream>
#include <cstring>
const double eps=1e-10;
const int maxm=11000;
int head[maxm],to[maxm],net[maxm];
int cnt;
double cost[maxm],dis[maxm];
int n,m;
void addedge(int u,int v,double c)
{
    cnt++;
    to[cnt]=v,cost[cnt]=c,net[cnt]=head[u],head[u]=cnt;
}
bool vis[maxm];
bool dfs(int now,double x)
{
    vis[now]=1;
    for(int i=head[now];i;i=net[i])
    if(dis[to[i]]>dis[now]+cost[i]-x)
    {
        dis[to[i]]=dis[now]+cost[i]-x;
        if(vis[to[i]]) return 1;
        else if(dfs(to[i],x)) return 1;
    }
    return vis[now]=0;
}
bool check(double mid)
{
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
     if(dfs(i,mid)) return 1;
    return 0;
}
int main()
{
    double l=1e9,r=-1e9;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        double c;
        scanf("%d%d%lf",&u,&v,&c);
        addedge(u,v,c);
        l=std::min(l,c);
        r=std::max(r,c);
    }
    while(r-l>eps)
    {
        double mid=(l+r)/2.0;
        if(check(mid)) r=mid;
        else l=mid;
    }
    return printf("%.8lf\n",l)*0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值