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

来源:互联网 发布:淘宝膜法世家是真的吗 编辑:程序博客网 时间:2024/05/01 04:08

链接: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)|1using 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