AcWing 361. 观光奶牛
Posted dmoransky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 361. 观光奶牛相关的知识,希望对你有一定的参考价值。
01规划
设答案为 (ans)。
二分答案,设当前二分值为 (mid)。
设一个环 (S) 的边权为 (t_1, t_2, t_3...),点权为 (f_1, f_2, f_3...)
若 (mid <= ans),即存在一个环(S)使得 (mid <= frac{sum f_i}{sum t_i}),变换一下:(sum(mid * t_i - f_i) <= 0)
否则,则 (mid > ans)
每次 (check) 的时候,一条 (u) 指向 (v),边权为 (w) 的边权变为:
(w * mid - f_u)。我们只需检查这个图是否存在负环即可。
时间复杂度
最坏情况存在长度为 (L) 的环, (sum t_i = L, sum f_i = 1000L)。故答案最大可能是 (1000)。
(Log_21000 approx 10)
(O(10*LP))。判负环的时间一般情况下低于 (O(LP))。
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 1005, M = 5005;
int n, q[N * M], m, f[N], cnt[N];
int head[N], numE = 0;
double dis[N];
bool vis[N];
struct E{
int next, v, w;
}e[M];
void add(int u, int v, int w) {
e[++numE] = (E) { head[u], v, w };
head[u] = numE;
}
bool inline check(double mid) {
int hh = 0, tt = -1;
for (int i = 1; i <= n; i++)
vis[i] = true, dis[i] = cnt[i] = 0, q[++tt] = i;
while(hh <= tt) {
int u = q[hh++];
vis[u] = false;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
double w = e[i].w * mid - f[u];
if(dis[u] + w < dis[v]) {
dis[v] = dis[u] + w;
cnt[v] = cnt[u] + 1;
if(cnt[v] >= n) return true;
if(!vis[v]) q[++tt] = v;
}
}
}
return false;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", f + i);
for (int i = 1, u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
double l = 0, r = 1000, eps = 1e-4;
while(r - l > eps) {
double mid = (l + r) / 2;
if(check(mid)) l = mid;
else r = mid;
}
printf("%.2lf
", r);
return 0;
}
以上是关于AcWing 361. 观光奶牛的主要内容,如果未能解决你的问题,请参考以下文章
[USACO07DEC]观光奶牛Sightseeing Cows
洛谷 P2868 [USACO07DEC]观光奶牛Sightseeing Cows
洛谷P2868 [USACO07DEC]观光奶牛 Sightseeing Cows