L i n k Link Link
l u o g u P 2868 luogu\ P2868 luogu P2868
D e s c r i p t i o n Description Description
大意就是在图上找一个环,求这个这个环的点权/边权的最大值
S a m p l e Sample Sample I n p u t Input Input
5 7
30
10
10
5
10
1 2 3
2 3 2
3 4 5
3 5 2
4 5 5
5 1 3
5 2 2
S a m p l e Sample Sample O u t p u t Output Output
6.00
S o l u t i o n Solution Solution
我们直接二分答案
m
i
d
mid
mid,若答案能更大, 则按题意有
F
/
T
>
m
i
d
F / T > mid
F/T>mid,变形一下得
F
−
m
i
d
∗
T
>
0
F - mid * T > 0
F−mid∗T>0, 那也就是
m
i
d
∗
T
−
F
<
0
mid * T - F < 0
mid∗T−F<0
我们把边权看为是
m
i
d
∗
T
[
i
]
−
F
[
x
]
mid * T[i] - F[x]
mid∗T[i]−F[x],即估计答案 * 原本的边权 - 点权,然后用spfa判断负环即可
C o d e Code Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1005;
int m, n, ans, l, r, t;
int f[N], h[N], cnt[N];
double dis[N];
bool vis[N];
struct node
{
int to, next, val;
}w[5005];
void add(int x, int y, int z)
{w[++t] = (node){y, h[x], z}; h[x] = t;}
bool spfa(double x)
{
queue<int>Q;
for (int i = 1; i <= N; ++i)
{
dis[i] = inf;
vis[i] = 0;
cnt[i] = 0;
}//初始化
vis[1] = 1;
dis[1] = 0;
Q.push(1);
while (Q.size())
{
int tot = Q.front();
Q.pop();
for (int i = h[tot]; i; i = w[i].next)
{
int to = w[i].to;
double val = x * w[i].val - f[tot];
if (dis[to] > dis[tot] + val)
{
dis[to] = dis[tot] + val;
cnt[to] = cnt[tot] + 1;//记录步数
if (!vis[to]) {
vis[to] = 1;
Q.push(to);
}
if (cnt[to] >= n) return 1;
}
}
vis[tot] = 0;
}
return 0;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d", &f[i]);
for (int i = 1; i <= m; ++i)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
}
ans = 0;
l = 0, r = inf;
while (l <= r)
{
int mid = (l + r) / 2;
if (spfa((double) mid / 10000)) l = mid + 1, ans = mid;// /10000是为了确定精度
else r = mid - 1;
}
double s = (double)ans / 10000;
printf("%.2lf", s);
}