[负环][二分]Link with Game Glitch 2022牛客多校第2场 D

48 篇文章 0 订阅

题目描述

Link is developing a game. In this game, players can craft things using various types of resources, and things crafted can also be used to craft other things.

Formally speaking, there are nnn types of items, numbered from 111 to nnn, and mmm recipes in the game. In the iii-th recipe, players can use k∗aik*a_ik∗ai​ items of the bib_ibi​-th type to craft k∗cik*c_ik∗ci​ items of the did_idi​-th type, where kkk can be any positive real number.

One day, he finds that one player owns more than 18,446,744,073,709,551,615 identical items, which causes a server crash. This is obviously impossible without using glitches.

Link soon finds out that there is something wrong with the crafting recipe. Players may get infinite resources by crafting some special things over and over again!

Link doesn't want to adjust the recipes one by one, so he simply added an argument www. Now players can use k∗aik*a_ik∗ai​ items of the bib_ibi​-th type to craft w∗k∗ciw*k*c_iw∗k∗ci​ items of the did_idi​-th type.

Link wonders: What's the maximum www that he can set so that no player can get infinite items by crafting things over and over again?
 

输入描述:

The first line contains two integers n,m(2≤n≤1000,2≤m≤2000)n,m(2 \leq n \leq 1000, 2 \leq m \leq 2000)n,m(2≤n≤1000,2≤m≤2000), which are the number of item types and the number of recipes.

Each of the next mmm lines contains four integers ai,bi,ci,di(1≤bi,di≤n,bi≠di,1≤ai,ci≤103)a_i,b_i,c_i,d_i(1 \leq b_i,d_i \leq n, b_i \neq d_i, 1 \leq a_i,c_i \leq 10^3)ai​,bi​,ci​,di​(1≤bi​,di​≤n,bi​​=di​,1≤ai​,ci​≤103), describing a recipe.

It is guaranteed that players can get infinite items using the recipes above (when w=1w=1w=1).

输出描述:

Output a real number www, which is the maximum www satisfying the condition.

Your answer is considered correct if its absolute or relative error does not exceed 10−610^{-6}10−6.

Formally, let your answer be aaa, and the jury's answer be bbb. Your answer is accepted if and only if ∣a−b∣max⁡(1,∣b∣)≤10−6\frac{|a - b|}{\max{(1, |b|)}} \le 10^{-6}max(1,∣b∣)∣a−b∣​≤10−6.

示例1

输入

3 3
1 1 2 2
1 2 2 1
1 3 1 1

输出

0.5000000000

题意: 给出n个物品,以及m条转换关系,每条转换关系用四个整数表示a,b,c,d,含义是可以把k*a的b物品转换为k*c的d物品,k可以取任意正值,由于这样可能导致物品无限再生,所以需要引入一个损耗参数w,也就是用k*a的b物品转换为w*k*c的d物品,询问最大的损耗参数w以保证不存在无限再生现象。

分析: 这道题目有点类似之前做过的一道汇率转换题,不过这道题目要多一个二分的步骤,由于w具有单调性,所以可以二分求出w的值,在每次二分的过程中跑一个spfa求正环,这样就可以求出最大的w值了,但是由于double值在spfa过程中可能会变得非常大,导致精度损失很大,所以可以对double值都取一个对数,然后乘法都转换为加法,或者define double long double也可以。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <vector> 
#include <queue>
#define inf 1e50
#define double long double
#define pdi pair<double, int>
using namespace std;

vector<pdi> g[1005];
double dis[1005];
bool vis[1005];
int num[1005];
int n, m;
const double eps = 1e-8;

bool check(double x){
	for(int i = 1; i <= n; i++){
		vis[i] = false;
		dis[i] = -inf;
		num[i] = 0;
	}
	dis[0] = 0;
	queue<int> q;
	q.push(0);
	while(q.size()){
		int now = q.front();
		q.pop();
		vis[now] = false;
		for(int i = 0; i < g[now].size(); i++){
			int to = g[now][i].second;
			double c = g[now][i].first;
			c += x;
			if(dis[to] < dis[now]+c){
				dis[to] = dis[now]+c;
				num[to] = num[now]+1;
				if(num[to] >= n+1) return true;
				if(!vis[to]){
					vis[to] = true;
					q.push(to); 
				}
			}
		}
	}
	return false;
}

signed main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i++){
		int a, b, c, d;
		scanf("%d%d%d%d", &a, &b, &c, &d);
		g[b].push_back(make_pair(log(1.0*c/a), d));
	}
	for(int i = 1; i <= n; i++)
		g[0].push_back(make_pair(0.0, i));
	double l = 0, r = 1.0;
	while(r-l > eps){
		double mid = (l+r)/2;
		if(check(log(mid))) r = mid;
		else l = mid;
	}
	printf("%.10Lf\n", l);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值