您的位置:首页 > 其它

poj 3621 Sightseeing Cows 【最优比例环】 【0-1分数规划 + SPFA判负环】

2015-09-02 17:09 351 查看
Sightseeing Cows

Time Limit: 1000MSMemory Limit: 65536K
Total Submissions: 8663Accepted: 2900
Description

Farmer John has decided to reward his cows for their hard work by taking them on a tour of the big city! The cows must decide how best to spend their free time.

Fortunately, they have a detailed city map showing the L (2 ≤ L ≤ 1000) major landmarks (conveniently numbered 1.. L) and the P (2 ≤ P ≤ 5000) unidirectional cow paths that join them. Farmer John will drive the
cows to a starting landmark of their choice, from which they will walk along the cow paths to a series of other landmarks, ending back at their starting landmark where Farmer John will pick them up and take them back to the farm. Because space in the city
is at a premium, the cow paths are very narrow and so travel along each cow path is only allowed in one fixed direction.

While the cows may spend as much time as they like in the city, they do tend to get bored easily. Visiting each new landmark is fun, but walking between them takes time. The cows know the exact fun values Fi (1 ≤ Fi ≤
1000) for each landmark i.

The cows also know about the cowpaths. Cowpath i connects landmark L1i to L2i (in the direction L1i -> L2i ) and requires time Ti (1
≤ Ti ≤ 1000) to traverse.

In order to have the best possible day off, the cows want to maximize the average fun value per unit time of their trip. Of course, the landmarks are only fun the first time they are visited; the cows may pass through the landmark more than once, but they
do not perceive its fun value again. Furthermore, Farmer John is making the cows visit at least two landmarks, so that they get some exercise during their day off.

Help the cows find the maximum fun value per unit time that they can achieve.

Input

* Line 1: Two space-separated integers: L and P

* Lines 2..L+1: Line i+1 contains a single one integer: Fi

* Lines L+2..L+P+1: Line L+i+1 describes cow path i with three space-separated integers: L1i , L2i , and Ti

Output

* Line 1: A single number given to two decimal places (do not perform explicit rounding), the maximum possible average fun per unit time, or 0 if the cows cannot plan any trip at all in accordance with the above rules.

Sample Input
5 7
30
10
10
5
10
1 2 3
2 3 2
3 4 5
3 5 2
4 5 5
5 1 3
5 2 2

Sample Output
6.00

大致题意:有一个N个点、M条有向边的图,给出每个点的点权和每条边的长度。现在让你求出一个环,使得该环里面所有点的点权之和sum 和所有边的长度总和len比值最大,若存在一个这样的环输出最大比值,否则输出0。

想法一:

用h[i]表示环中i点的点权。len[i]表示环中到达i点的边的长度。
分析:我们设最优解 o = sigma(h[i]) / sigma(len[i])。 则有sigma(h[i]) - o * sigma(len[i]) = 0。
首先我们要明确所有枚举的值mid只有小于或等于o才有意义。

用sum记录环中所有点的点权和,len记录环中所有边的长度。则有:
一、如果图中所有环均满足——sum - mid * len < 0,说明mid值过大并且该值是不合法的,只需要减小mid值。
二、如果有一个环满足sum - mid * len > 0,说明mid值过小但这个值却是合法的,需要更新结果并增大mid值。
我们只能选择——判断情况二是否成立,情况二显然是让你找正环,正环? 反过来求负环不可以么。


想法二:转化问题——求解环里面边的长度总和len和点权之和sum的最小比值。
用h[i]表示环中i点的点权。len[i]表示环中到达i点的边的长度。

我们设最优解 o = sigma(len[i]) / sigma(h[i])。 则有o * sigma(len[i]) - sigma(h[i]) = 0。
首先我们要明确所有枚举的值mid只有大于或等于o才有意义。

用sum记录环中所有点的点权和,len记录环中所有边的长度。则有:
一、如果有一个环满足len * mid - sum < 0,说明mid值过小但这个值却是合法的,需要更新结果并增大mid值;
二、如果图中所有环均满足——sum - mid * len >
0,说明mid值过大并且该值是不合法的,只需要减小mid值。
这样不就好写了吗?对于当前枚举的mid值,只需求解图中是否存在一个负环即可。

注意精度!!!
AC代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define MAXN 1001
#define MAXM 6000
#define INF 0x3f3f3f3f
#define eps 1e-4//精度
using namespace std;
struct Edge
{
    int from, to;
    double val;
    int next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int N, M;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, double w)
{
    Edge E = {u, v, w, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
double Max;
void getMap()
{
    int a, b;
    double c;
    while(M--)
    {
        scanf("%d%d%lf", &a, &b, &c);
        addEdge(a, b, c);
    }
}
double h[MAXN], dist[MAXN];
bool vis[MAXN];
int used[MAXN];
bool SPFA(double o)
{
    queue<int> Q;
    memset(vis, false, sizeof(vis));
    for(int i = 1; i <= N; i++)
        dist[i] = INF;
    memset(used, 0, sizeof(used));
    dist[1] = 0;
    vis[1] = true;
    used[1] = 1;
    Q.push(1);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            Edge E = edge[i];
            double p = o * E.val - h[E.to];
            if(dist[E.to] - dist[u] - p > eps)
            {
                dist[E.to] = dist[u] + p;
                if(!vis[E.to])
                {
                    used[E.to]++;
                    if(used[E.to] > N)//存在负环
                        return true;
                    vis[E.to] = true;
                    Q.push(E.to);
                }
            }
        }
    }
    return false;
}
void solve()
{
    double l = 0, r = Max / 2, mid;
    double ans = 0;
    while(r - l >= eps)
    {
        mid = (l + r) / 2;
        if(SPFA(mid))//存在负环
        {
            ans = mid;//更新
            l = mid;
        }
        else//不存在负环 不更新
            r = mid;
    }
    printf("%.2lf\n", ans);
}
int main()
{
    while(scanf("%d%d", &N, &M) != EOF)
    {
        Max = 0;
        for(int i = 1; i <= N; i++)
            scanf("%lf", &h[i]), Max = max(Max, h[i]);
        init();
        getMap();
        solve();
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: