bzoj1486 [HNOI2009]最小圈 【最小比例环 01分数规划】

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1486

题意:中文题,和上题相似,求的是sigma(c)/k最小的环,c是边的权值,k为选了多少点。

分析:

还是找简单还,证明在上一题。

如果一个比例L使得sigma(c)-L*K是个负权环,那么可能存在一个小于L的比例R使得sigma(c)-R*K是个负权环,这就是01分数规划的套路。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 3010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CLRS(a,b,Size) memset((a),(b),sizeof((a[0]))*(Size+1))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
const double eps=1e-9;
struct edge {
    int v,next;
    double w;
}e[Mm];
int head[Mn],tot;
void addedge(int u,int v,double w) {
    e[tot].v=v;
    e[tot].w=w;
    e[tot].next=head[u];
    head[u]=tot++;
}
int vis[Mn],st;
double dis[Mn];
bool dfs(int u,double x) {
    vis[u]=st;
    for(int i=head[u];~i;i=e[i].next) {
        int v=e[i].v;
        double w=e[i].w-x;
        if(dis[v]>dis[u]+w) {
            if(vis[v]==st) return true;
            dis[v]=dis[u]+w;
            if(dfs(v,x)) return true;
        }
    }
    vis[u]=-1;
    return false;
}
int n;
bool check(double x) {
    CLR(vis,0);
    CLR(dis,0);
    for(st=1;st<=n;st++) {
        if(vis[st]==0&&dfs(st,x)) return true;
    }
    return false;
}
int main() {
    int m,u,v;
    double w;
    CLR(head,-1);
    tot=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
        scanf("%d%d%lf",&u,&v,&w);
        addedge(u,v,w);
    }
    double l=-10000.0,r=10000.0;
    while((r-l)>eps) {
        double mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid;
    }
    printf("%.8f\n",r);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值