poj 3621 二分+spfa

题意:给出一个有向图,问求一个回路,使得回路上的点权之和/边权之和最大。

这题主要是分析出如何确定ans值。我们将(a1*x1+a2*x2+..+an*xn)/(b1*x1+b2*x2+..+bn*xn)=L,转换为:x1*(a1-b1*L)+x2*(a2-b2*L)+...xn*(an-bn*L)=0

则每次枚举L的值,spfa中边权值为len[]*L-a[],若存在负环回路(即一个点访问次数超过n次)则表示L的值小了,增大L值;反之减小L值.

 

 

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define MAXN 1052
#define inf 10000000
using namespace std;
struct Edge{
    int u,len,next;
}edge[5*MAXN];
int temp,n,m;
int head[MAXN],a[MAXN];
void addEdge(int u,int v,int c)
{
    edge[temp].u=v;
    edge[temp].len=c;
    edge[temp].next=head[u];
    head[u]=temp;
    temp++;
}
double dis[MAXN];
    bool vis[MAXN];
    int num[MAXN];
    int que[MAXN*MAXN];
bool spfa(double mid)
{
    double val;
    for(int i=0;i<=n;i++)
    {
        dis[i]=inf;
        vis[i]=false;
        num[i]=0;
    }
    dis[1]=0;

    int headt,tail;
    headt=0;tail=0;
    que[tail++]=1;
    vis[1]=true;
    num[1]++;
    while(headt!=tail)
    {
        int v=que[headt];
        headt++;
        vis[v]=false;
        for(int i=head[v];i!=-1;i=edge[i].next)
        {
            int u=edge[i].u;
            val=mid*edge[i].len-a[u];
            if(dis[v]+val<dis[u])
            {
                dis[u]=dis[v]+val;
                if(!vis[u])
                {
                    que[tail++]=u;
                    vis[u]=true;
                    num[u]++;
                    if(num[u]>=n)
                    {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}


int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        temp=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
    {
        int v,w,c;
        scanf("%d%d%d",&v,&w,&c);
        addEdge(v,w,c);
    }
    double  mid=0;double ans=0;
    double l=0;double r=2000;
    while(r-l>=0.001)
    {
        mid=(l+r)/2.0;

        if(spfa(mid))
        {
            r=mid; //减小ans;
        }
        else
        {
            ans=mid;
            l=mid;
        }
    }
    printf("%.2lf\n",ans);

    }
    return 0;
}


 

posted @ 2013-07-29 17:23  amourjun  阅读(163)  评论(0编辑  收藏  举报