POJ 3621 (最优比率环 二分+SPFA)

来源:互联网 发布:linux 发送at指令 编辑:程序博客网 时间:2024/05/02 01:08

题目链接:点击这里

题意:找出一个环, 最大化viEi.

假设答案是ans.那么有viEi=ans也就是viansEi=0.因为是一个环,所以环上每个点都被算了两次,所以可以给每条边对应一个Fi表示边上两个节点权值和的一半,所以所求就是FiansEi=0.二分枚举ans, 如果找到一个负环,说明ans偏小,否则ans偏大.

#include <cstdio>#include <iostream>#include <cstring>#include <queue>#include <cmath>#include <algorithm>#define Clear(x,y) memset (x,y,sizeof(x))#define FOR(a,b,c) for (int a = b; a <= c; a++)#define REP(a,b,c) for (int a = b; a >= c; a--)#define fi first#define se second#define pii pair<int, int>#define pli pair<long long, int>#define pb push_back#define mod 1000000007using namespace std;#define maxn 1005#define maxm 5005int n, m;int val[maxn];struct node {    int u, v, num, next;    double w;}edge[maxm];int head[maxn], cnt;void add_edge (int u, int v, int w) {    edge[cnt].num = w;    edge[cnt].u = u, edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;}bool vis[maxn];int top, num[maxn];double d[maxn];bool spfa (double ans) {    queue <int> q; while (!q.empty ()) q.pop ();    for (int i = 1; i <= n; i++) {        vis[i] = 1;        d[i] = 0;        q.push (i);        num[i] = 1;    }    for (int i = 0; i < cnt; i++) {        node &e = edge[i];        e.w = (val[e.u]+val[e.v])/2.0-ans*e.num;    }    while (!q.empty ()) {        int u = q.front (); q.pop ();        vis[u] = 0;        for (int i = head[u]; i+1; i = edge[i].next) {            int v = edge[i].v;            if (d[v] < d[u]+edge[i].w) {                d[v] = d[u]+edge[i].w;                if (!vis[v]) {                    vis[v] = 1;                    q.push (v);                    if (++num[v] > n)                        return 1;                }            }        }    }    return 0;}int main () {    //freopen ("more.in", "r", stdin);    while (scanf ("%d%d", &n, &m) == 2) {        double l = 0, r = 0;        for (int i = 1; i <= n; i++) {            scanf ("%d", &val[i]);            r += val[i];        }        Clear (head, -1);        cnt = 0;        for (int i = 1; i <= m; i++) {            int u, v, w; scanf ("%d%d%d", &u, &v, &w);            add_edge (u, v, w);        }        while (r-l > 1e-5) {            double mid = (l+r)/2;            if (spfa (mid)) l = mid;            else r = mid;        }        printf ("%.2f\n", l);    }    return 0;}
0 0
原创粉丝点击