[BZOJ1486][HNOI2009]最小圈

Posted 租酥雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1486][HNOI2009]最小圈相关的知识,希望对你有一定的参考价值。

[BZOJ1486][HNOI2009]最小圈

bzoj
luogu

题意

你有一张有向图,保证连通,保证存在至少一个环。
你需要找到一个环,最小化环的平均权值。
环的平均值定义为环的总权值除以环长。

sol

分数规划。可以看做每条边的\(b_i=1\)
二分一个\(mid\),令\(d_i=w_i-mid\),然后判断图中是否存在负环。
判负环用最朴素的\(O(n^2)\)算法即可。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 10005;
struct edge{int to,nxt;double w;}a[N];
int n,m,head[N],cnt,vis[N];
double dis[N];
void link(int u,int v,double w){
    a[++cnt]=(edge){v,head[u],w};head[u]=cnt;
}
bool cir(int u,double k){
    vis[u]=1;
    for (int e=head[u];e;e=a[e].nxt)
        if (dis[a[e].to]>dis[u]+a[e].w-k){
            dis[a[e].to]=dis[u]+a[e].w-k;
            if (vis[a[e].to]||cir(a[e].to,k)) return true;
        }
    vis[u]=0;return false;
}
bool check(double k){
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    for (int i=1;i<=n;++i) if (cir(i,k)) return true;
    return false;
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;++i){
        int u,v;double w;
        scanf("%d %d %lf",&u,&v,&w);
        link(u,v,w);
    }
    double l=-2e7,r=2e7;
    while (r-l>1e-9){
        double mid=(l+r)/2;
        if (check(mid)) r=mid;
        else l=mid;
    }
    printf("%.8lf\n",l);
    return 0;
}

以上是关于[BZOJ1486][HNOI2009]最小圈的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1486: [HNOI2009]最小圈

BZOJ_1486_[HNOI2009]最小圈_01分数规划

[BZOJ1486][HNOI2009]最小圈

bzoj 1486: [HNOI2009]最小圈

[BZOJ1486][HNOI2009]最小圈

bzoj1486 HNOI2009—最小圈