题意
传送门 AcWing 394 最优高铁环
题解
设图中边权为 w w w,最大化图中环的值
∑ w i ∑ 1 \frac{\sum w_i}{\sum 1} ∑1∑wi 0 / 1 0/1 0/1 分数规划问题,转换为图中存在某个环,使下式满足的最大 x x x
∑ w i ∑ 1 > x \frac{\sum w_i}{\sum 1}>x ∑1∑wi>x 二分答案,边权取 x − w i x-w_i x−wi,判定负环即可。
题中有向图不保证连通性,使用基于 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;
}