You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

69 lines
2.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 1010, M = 5010;
int n, m;
int f[N], cnt[N];
double dist[N];
bool st[N];
const double eps = 1e-4;
// 邻接表
int idx, h[N], e[M], w[M], ne[M];
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
// dfs 判负环
// Accepted 35 ms
bool dfs(int u, double mid) {
if (st[u]) return 1; // 如果又见u说明有环
bool flag = 0; // 我及我的后代们是不是有环?
st[u] = 1; // 记录u出现过
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
// 更新最小值,判负环
if (dist[v] > dist[u] + w[i] * mid - f[u]) { // 我都初始化为0了你还要修改我那你是负数
dist[v] = dist[u] + w[i] * mid - f[u];
flag = dfs(v, mid); // 检查一下我的下一个节点v,它要是能检查到负环,它的观点就代表我的观点
if (flag) break; // 不直接return就是为了照顾下面的回溯
}
}
st[u] = 0; // 回溯,其实本质上就不想每次重头memset(st,0,sizeof st); 随用随清理,好习惯~
return flag;
}
bool check(double mid) {
memset(dist, 0, sizeof dist); // dist初始化为0
for (int i = 1; i <= n; i++)
if (dfs(i, mid)) return true; // 以i点出发是否有负环
return false;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &f[i]); // 每个点都有一个权值f[i]
// 初始化邻接表
memset(h, -1, sizeof h);
int a, b, c;
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &a, &b, &c);
add(a, b, c);
}
// 浮点数二分
double l = 0, r = 1000;
// 左边界很好理解因为最小是0
// Σf[i]最大1000*n,Σt[i]最小是1*n,比值最大是1000
// 当然也可以无脑的设置r=INF并不会浪费太多时间logN的效率你懂的
// 因为保留两位小数所以这里精度设为1e-4
while (r - l > eps) {
double mid = (l + r) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.2lf\n", l);
return 0;
}