BZOJ1486: [HNOI2009]最小圈

【传送门:BZOJ1486


简要题意:

  给出一张n个点m条边的连通图,求出这个图中,所有环中,环上的边权和/环上的点数的最小值


题解:

  直接01分数规划二分答案,然后类似与SPFA的dfs判负环就行了


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define Maxn 3100
#define eps 1e-9
using namespace std;
struct node{int x,y,next;double c;}a[21000];int len,last[Maxn];
void ins(int x,int y,double c){a[++len]=(node){x,y,last[x],c};last[x]=len;}
double d[Maxn];
bool v[Maxn];
bool dfs(int x)
{
    v[x]=true;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(d[y]-(d[x]+a[k].c)>-eps)
        {
            if(v[y]==true) return true;
            else
            {
                d[y]=d[x]+a[k].c;
                if(dfs(y)==true) return true;
            }
        }
    }
    v[x]=false;
    return false;
}
int n;
bool check(double c)
{
    for(int i=1;i<=len;i++) a[i].c-=c;
    bool bk=false;
    memset(v,false,sizeof(v));
    memset(d,0,sizeof(d));
    for(int i=1;i<=n;i++)
    {
        d[i]=0.0;
        if(dfs(i)==true){bk=true;break;}
    }
    for(int i=1;i<=len;i++) a[i].c+=c;
    return bk;
}
int main()
{
    int m;
    scanf("%d%d",&n,&m);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=m;i++)
    {
        int x,y;double c;
        scanf("%d%d%lf",&x,&y,&c);
        ins(x,y,c);
    }
    double l=-10000000.0,r=10000000.0,ans;
    while(r-l>eps)
    {
        double mid=(l+r)/2.0;
        if(check(mid)==true)
        {
            ans=mid;
            r=mid;
        }
        else l=mid;
    }
    printf("%.8lf\n",ans);
    return 0;
}

 

posted @ 2018-12-22 11:49  Star_Feel  阅读(...)  评论(...编辑  收藏