AcWing 384 二分 + 判定负环

题意

传送门 AcWing 394 最优高铁环

题解

设图中边权为 w w w,最大化图中环的值
∑ w i ∑ 1 \frac{\sum w_i}{\sum 1} 1wi 0 / 1 0/1 0/1 分数规划问题,转换为图中存在某个环,使下式满足的最大 x x x
∑ w i ∑ 1 > x \frac{\sum w_i}{\sum 1}>x 1wi>x 二分答案,边权取 x − w i x-w_i xwi,判定负环即可。

题中有向图不保证连通性,使用基于 D F S DFS DFS S P F A SPFA SPFA 算法判定负环。基本思想是,若图中从节点 i i i 开始松弛,最终可以松弛 i i i,则图中存在负环。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5005, maxm = 50005;
const double eps = 1e-2, inf = 1e9;
int M, id[128], sd[128], nx, sx[maxn];
int tot, head[maxn], to[maxm], tc[maxm], nxt[maxm];
double ds[maxn], cost[maxm];
bool vs[maxn];

inline void add(int x, int y, int z)
{
    
    
    to[++tot] = y, tc[tot] = z, nxt[tot] = head[x], head[x] = tot;
}

bool dfs(int x)
{
    
    
    vs[x] = 1;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i];
        double z = cost[i];
        if (ds[x] + z < ds[y])
        {
    
    
            ds[y] = ds[x] + z;
            if (vs[y] || dfs(y))
                return 1;
        }
    }
    vs[x] = 0;
    return 0;
}

bool judge(double x)
{
    
    
    for (int i = 1; i <= tot; ++i)
        cost[i] = x - tc[i];
    fill(ds + 1, ds + nx + 1, inf);
    memset(vs, 0, sizeof(vs));
    for (int i = 1; i <= nx; ++i)
        if (dfs(i))
            return 1;
    return 0;
}

int main()
{
    
    
    id['S'] = 1, id['G'] = 2, id['D'] = 3, id['T'] = 4, id['K'] = 5;
    sd['S'] = 1000, sd['G'] = 500, sd['D'] = 300, sd['T'] = 200, sd['K'] = 150;
    scanf("%d", &M);
    for (int i = 1; i <= M; ++i)
    {
    
    
        char s[120];
        int j = 1, n = 0, t = 0, x = 0, y = 0, z = 0;
        scanf("%s", s + 1), n = strlen(s + 1);
        while (j <= n)
        {
    
    
            char c = s[j];
            y = (id[c] - 1) * 1000, z += sd[c], t = 0;
            for (c = s[++j]; j <= n && '0' <= c && c <= '9'; c = s[++j])
                t = (t << 1) + (t << 3) + c - '0';
            y += t;
            if (!x)
                x = y;
        }
        if (!sx[x])
            sx[x] = ++nx;
        if (!sx[y])
            sx[y] = ++nx;
        add(sx[x], sx[y], z);
    }
    double lb = 0, ub = 20000 * nx + 1;
    while (ub - lb > eps)
    {
    
    
        double mid = (lb + ub) / 2;
        if (judge(mid))
            lb = mid;
        else
            ub = mid;
    }
    printf("%.0f\n", abs(lb) < eps ? -1 : lb);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/114840293