题解:P10951 最优高铁环
考虑套路 01 分数规划。对于每个作为路线的首尾的车次,当作一个点,对于每条路线首连尾。根据 01 分数规划的套路,二分答案然后建图在图上找正环即可。
建议评蓝。另外这题实际上是不规范的,因为他需要 SPFA 来判负环,数据却不对。为了通过这题,我们需要卡时,具体的,在 SPFA 循环次数过多时,直接认为有正环。
// Problem: P10951 最优高铁环
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P10951
// Memory Limit: 512 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
/*
(sigma v)/n>=mid
(sigma v)>=mid*n
(sigma v)-mid*n>=0
(sigma v-mid)>=0
*/
#include <bits/stdc++.h>
#define upp(a, x, y) for (int a = x; a <= y; a++)
#define dww(a, x, y) for (int a = x; a >= y; a--)
#define pb(x) push_back(x)
#define endl '\n'
#define x first
#define y second
#define PII pair<int, int>
using namespace std;
const int N = 1e5 + 10, INF = 0x3f3f3f3f3f3f3f3f;
int h[N], ne[N], e[N], w[N], idx, cnt;
double dist[N];
int in[N];
bool st[N];
unordered_map<string, int> ha;
int hav(string x) {
if (!ha[x]) return ha[x] = ++cnt;
return ha[x];
}
int va(char g) {
if (g == 'S')
return 1000;
else if (g == 'G')
return 500;
else if (g == 'D')
return 300;
else if (g == 'T')
return 200;
else if (g == 'K')
return 150;
return 0;
}
void add(int a, int b, int c) {
e[idx] = b;
ne[idx] = h[a];
w[idx] = c;
h[a] = idx++;
}
int m;
bool spfa(double mid) {
queue<int> qq;
memset(st, 0, sizeof st);
memset(in, 0, sizeof in);
upp(i, 1, cnt) {
dist[i] = 0;
st[i] = 1;
qq.push(i);
}
int sum = 0;
while (qq.size()) {
auto iter = qq.front();
st[iter] = 0;
qq.pop();
for (int i = h[iter]; i != -1; i = ne[i]) {
int j = e[i];
if (dist[j] < dist[iter] + w[i] - mid) {
dist[j] = dist[iter] + w[i] - mid;
if (++in[j] > cnt) return 1;
if (++sum > 100000) return 1;
if (!st[j]) {
st[j] = 1;
qq.push(j);
}
}
}
}
return 0;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
memset(h, -1, sizeof h);
cin >> m;
upp(i, 1, m) {
string str;
cin >> str;
int st = -1, ed = -1, c = 0;
string now = "";
upp(j, 0, (int)str.size() - 1) {
if (str[j] == '-') {
if (st == -1) st = hav(now);
now = "";
} else
now += str[j];
c += va(str[j]);
}
ed = hav(now);
add(st, ed, c);
}
double l = 0, r = 4e9;
while (r - l > 1e-2) {
auto mid = (l + r) / 2;
if (spfa(mid))
l = mid;
else
r = mid;
}
if (!spfa(l))
cout << -1 << endl;
else
cout << setprecision(0) << fixed << l << endl;
return 0;
}