洛谷 P3199 [HNOI2009]最小圈

题目背景

如果你能提供题面或者题意简述,请直接在讨论区发帖,感谢你的贡献。

题目描述

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

输入输出格式

输入格式:

 

第一行2个正整数,分别为n和m

以下m行,每行3个数,表示边连接的信息,

 

输出格式:

 

一行一个数,表示最小圈的值,保留8位小数。

 

输入输出样例

输入样例#1:
4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
输出样例#1:
3.66666667

说明

若设边权为vv,那么n\le 3000,m\le 10000,v\le 50000n3000,m10000,v50000

思路:分数规划

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 10010
using namespace std;
int n,m,tot;
double l,r,mid,ans;
int vis[MAXN];
double dis[MAXN],cap[MAXN];
int to[MAXN],net[MAXN],head[MAXN];
void add(int u,int v,double w){
    to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot;
}
bool spfa(int now){
    vis[now]=1;
    for(int i=head[now];i;i=net[i])
        if(dis[to[i]]>dis[now]-mid+cap[i]){
            dis[to[i]]=dis[now]-mid+cap[i];
            if(vis[to[i]]||spfa(to[i])){
                vis[to[i]]=0;
                return true;
            }
        }
    vis[now]=0;
    return false;
}
bool chack(){
    memset(vis,0,sizeof(vis));
    memset(dis,0,sizeof(dis));
    for(int i=1;i<=n;i++)    
        if(spfa(i))    return false;
    return true;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int a,b;
        double c;
        scanf("%d%d%lf",&a,&b,&c);
        add(a,b,c);
    }
    l=0;r=100000;
    while(r-l>0.000000001){
        mid=(l+r)/2;
        if(chack()){
            ans=mid;
            l=mid;
        }
        else r=mid;
    }
    printf("%.8lf",ans);
}
/*
4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
*/

 

posted @ 2017-10-17 16:19  一蓑烟雨任生平  阅读(168)  评论(0编辑  收藏  举报