【SPFA】[USACO07DEC] Sightseeing Cows G

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

【SPFA】[USACO07DEC] Sightseeing Cows G_第1张图片
大意就是在图上找一个环,求这个这个环的点权/边权的最大值

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
#include
#include
#include

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

你可能感兴趣的:(图论,SPFA,SPFA,01分数规划)