【SPFA】[USACO07DEC] Sightseeing Cows G

14 篇文章 0 订阅

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 FmidT>0, 那也就是 m i d ∗ T − F < 0 mid * T - F < 0 midTF<0
我们把边权看为是 m i d ∗ T [ i ] − F [ x ] mid * T[i] - F[x] midT[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); 
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值