1. 程式人生 > 其它 >做題記錄 Luogu P4926

做題記錄 Luogu P4926

Luogu P4926 [1007]倍殺測量者

取對數化除為減。

或者用乘積最短路。

注意圖不一定連通。

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
const double eps = 1e-12;
struct graph
{
	int opt, u, v;
	double w;
};
graph g[N];
deque<int> q;
int first[N], Next[N], to[N], tot;
double w[N], dis[N];
int vis[N], cnt[N], score[N], n, s, t;
void add(int x, int y, double z)
{
	Next[++tot] = first[x];
	first[x] = tot;
	to[tot] = y;
	w[tot] = z;
	return;
}
int spfa(int x, double mid)
{
	for(int i = 0; i <= n; i++)
	{
		dis[i] = 1;
		q.push_front(i);
	}
	memset(vis, 0, sizeof(vis));
	memset(cnt, 0, sizeof(cnt));
	vis[x] = 1;
	while(!q.empty())
	{
		int u = q.front();
		q.pop_front();
		vis[u] = 0;
		for(int i = first[u]; i; i = Next[i])
		{
			int v = to[i];
			if(dis[u] * w[i] > dis[v])
			{
				dis[v] = dis[u] * w[i];
				if(!vis[v])
				{
					if(++cnt[v] >= n + 1)
					{
						return 0;
					}
					vis[v] = 1;
					if(q.empty() || dis[v] < dis[q.front()])
					{
						q.push_front(v);
					}
					else
					{
						q.push_back(v);
					}
				}
			}
		}
	}
	return 1;
}
int check(double mid)
{
	tot = 0;
	memset(first, 0, sizeof(first));
	while(!q.empty())
	{
		q.pop_front();
	}
	for(int i = 1; i <= s; i++)
	{
		if(g[i].opt == 1)
		{
			add(g[i].v, g[i].u, g[i].w - mid);
		}
		else
		{
			add(g[i].v, g[i].u, 1.0 / (g[i].w + mid));
		}
	}
	for(int i = 1; i <= n; i++)
	{
		if(score[i])
		{
			add(0, i, score[i]);
			add(i, 0, 1.0 / score[i]);
		}
	}
	return spfa(0, mid);
}
int main()
{
	scanf("%d%d%d", &n, &s, &t);
	for(int i = 1; i <= s; i++)
	{
		scanf("%d%d%d%lf", &g[i].opt, &g[i].u, &g[i].v, &g[i].w);
	}
	int k, x;
	for(int i = 1; i <= t; i++)
	{
		scanf("%d%d", &k, &x);
		score[k] = x;
	}
	double l = 0, r = 1e9, mid, ans = -1;
	while(r - l > eps)
	{
		mid = (l + r) / 2;
		if(!check(mid))
		{
			l = ans = mid;
		}
		else
		{
			r = mid;
		}
	}
	printf("%lf", ans);
}