poj3621 Sightseeing Cows(二分+spfa)

题目链接:http://poj.org/problem?id=3621

 

题意:求一个环路,欢乐值 / 总路径最大(欢乐值是每个点权,边有边权)

 

思路:ans=  val[i]/ w[i]   (假设val[i]为点权,w[i]为边权)

 ans*w[i]-val[i] = 0  当我们要找最大的ans时,且要保留精度很明显要用二分,寻找最大ans。

哪怎么判定有环呢?  我们知道 spaf是可以判断是否有负环的。

我们将spfa以前的边权改为   ans*w[i]-val[i]  如果有负环则说明,ans偏小了(很明显,有负环表明环内ans*w[i]-val[i]之和<0,要增大ans才能使之和等于0),否则ans偏大。

 

交到G++wa了一发, 在G++环境下,对于double 类型 真正的标准是用%lf输入,用%f输出。交c++就不用,因为 对于double 类型用%lf 输入用%lf输出是window 环境下VC的标准但不是真正的标准。

 

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1500; 
const int maxm=5500;
struct node{
    int u,v,w,nxt;
}e[maxm];
int head[maxn],val[maxn],num[maxn];
bool vis[maxn];
double d[maxn];
int n,m,cnt=0;

void add(int u,int v,int w)
{
    e[cnt].u=u;
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}

bool spfa(double x)
{
    memset(vis,0,sizeof(vis));
    memset(num,0,sizeof(num));
    queue<int> q;
    for(int i=1;i<=n;i++)
        d[i]=inf;
    d[1]=0;
    vis[1]=1;
    q.push(1);
    num[1]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].nxt)
        {
            int v=e[i].v;
            int w=e[i].w;
            double sum=-val[u]+x*w;
            if(d[v]>d[u]+sum)
            {
                d[v]=d[u]+sum;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                    num[v]++;
                    if(num[v]>n)
                        return true;
                }
            }
        }
    }
    return false;
}

int main()
{
    cnt=0;
    int u,v,w;
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    double l=0,r=10000,mid;
    while(r-l>0.001)
    {
        mid=(r+l)/2;
        if(spfa(mid))
            l=mid;
        else
            r=mid;
    }
    printf("%.2lf\n",l);
    return 0;
}

 

上一篇:dp(01背包问题)


下一篇:javascript – jsdoc别名方法名称