poj 3621 0/1分数规划求最优比率生成环

思路:以val[u]-ans*edge[i].len最为边权,判断是否有正环存在,若有,那么就是ans小了。否则就是大了。

在spfa判环时,先将所有点进队列。

#include<iostream>

#include<cstdio>

#include<queue>

#include<cstring>

#include<algorithm>

#include<cmath>

#define Maxn 1010

#define Maxm 6000

#define inf 1e10

#define eps 1e-4

using namespace std;

int vi[Maxn];

struct Edge{

    int u,v,next;

    double len;

}edge[Maxm];

double dis[Maxn],val[Maxn];

int head[Maxn],e,n,cnt[Maxn];

void add(int u,int v,double len)

{

    edge[e].u=u,edge[e].v=v,edge[e].len=len,edge[e].next=head[u],head[u]=e++;

}

void init()

{

    e=0;

    memset(vi,0,sizeof(vi));

    memset(cnt,0,sizeof(cnt));

    memset(head,-1,sizeof(head));

}

int spfa(double ans)

{

    int i,j,v,u;

    queue<int> q;

    memset(cnt,0,sizeof(cnt));

    for(i=1;i<=n;i++){

        dis[i]=0;

        q.push(i);

        vi[i]=1;

    }

    while(!q.empty()){

        int u=q.front();

        cnt[u]++;

        q.pop();

        vi[u]=0;

        for(i=head[u];i!=-1;i=edge[i].next){

            v=edge[i].v;

            double d=val[u]-ans*edge[i].len;

            if(dis[v]<dis[u]+d){

                dis[v]=dis[u]+d;

                cnt[v]++;

                if(cnt[v]>=n) return 1;

                if(!vi[v]){

                    q.push(v);

                    vi[v]=1;

                }

            }

        }

    }

    return 0;

}

int main()

{

    int i,j,a,b,m;

    double c;

    while(scanf("%d%d",&n,&m)!=EOF){

        init();

        for(i=1;i<=n;i++)

            scanf("%lf",val+i);

        for(i=1;i<=m;i++){

            scanf("%d%d%lf",&a,&b,&c);

            add(a,b,c);

        }

        double l=0,r=2000,mid;

        while(r-l>eps){

            mid=(l+r)/2;

            if(spfa(mid))

                l=mid;

            else

                r=mid;

        }

        printf("%.2lf\n",l);

    }

    return 0;

}

你可能感兴趣的:(poj)