Files
python/TangDou/AcWing/MinusCircle/361_dfs.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

69 lines
2.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}