2022牛客多校训练(2) D. Link with Game Glitch

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 nn types of items, numbered from 1 to n, and mm recipes in the game. In the i-th recipe, players can use k∗ai​ items of the bi​-th type to craft k∗ci​ items of the di​-th type, where k 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 w. Now players can use k∗ai​ items of the bi​-th type to craft w∗k∗ci​ items of the di​-th type.

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

题意:

第一行输入n,m,有n类物品,给每类物品编号1~n,有m种配方。接下来m行  包含四个整数 a b c d ,代表用a个b类物品,可以制造出c个d类物品。

然而存在无限制造的情况,比如消耗1个1类物品制造2个2类物品 ,一个2类物品有可以制造2个1类物品,现在为了杜绝这种现象,将消耗a个b制造c个d变为了消耗a个b制造c*w个d。求满足不能无限制造情况下的最大w。

思路:

如果无限制造,则必须成环,二分这个w,w一定是在0~1之间的一个数。建图,a,b,c,d建立从 b到d的边,权值为c/a,然后用spfa判环。如果存在环,且这个环是越造越少的,即不能无限制造,那么用spfa肯定是一直早跑这个环的,即遍历次数很多,用这个来判定w是否合适。如果不能无限制造代表我们的w可以更大一点,反之让w更小一点。然后精度在1e-6。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

const int MAXN = 1010;
const int MAXM = 3010;
const double eps=0.00000001;
int n,m,num,head[MAXN],cnt[MAXN];
double dis[MAXN];
bool vis[MAXN];
struct edge
{
	int to,next;
	double w;
}e[MAXM];
inline void add(int u,int v,double w)
{
	e[++num].to=v;
	e[num].w=w;
	e[num].next=head[u];
	head[u]=num;
}
inline bool spfa(double w)
{
	for(int i=1;i<=n;i++)
	{
		dis[i]=1;
		vis[i]=cnt[i]=1;
	}
	queue<int> q;
	int u,v;
	for(int i=1;i<=n;i++)
	{
		q.push(i);
	}
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].next)
		{
			v=e[i].to;
			if(dis[v]<=dis[u]*e[i].w*w)
			{
				dis[v]=dis[u]*e[i].w*w;
				cnt[v]=cnt[u]+1;
				if(cnt[v]>n)return 1;
				if(vis[v]==0)
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return 0;
}
int main()
{
	cin>>n>>m;
	for(int i=1,a,b,c,d;i<=m;i++)
	{
		scanf("%d%d%d%d",&a,&b,&c,&d);
		add(b,d,1.0*c/a);
	}
	double l=0;double r=1.0;
	while(r-l>=eps)
	{
		double mid=(l+r)/2;
		if(spfa(mid))
		{
			r=mid;
		}
		else
		{
			l=mid;
		}
	}
	printf("%.7lf\n",l);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值