• Link with Game Glitch(spfa判负环)


    "蔚来杯"2022牛客暑期多校训练营2

    Problem

    给出n种物品,这些物品可以进行转换。给出m条转换规则,形如: a a a b b b 物品 可以转换为 c × w c \times w c×w d d d 物品。问: w w w 最大取多少,才能使这些物品无法转换成无限多的物品。

    Solution

    明显就是一道图论题目。边: c → d c \to d cd, 边权: c w a \frac{cw}{a} acw

    1. 若要使无法转换成无限多的物品,那么就需要判断是否存在这样的一个“环”。
      假设:这个环上的边权为 e i e_i ei, 环上有 k k k 个节点
      那么,当满足 e 1 × e 2 × . . . × e k > 1 e_1 \times e_2 \times ... \times e_k > 1 e1×e2×...×ek>1 时, 则可以转换成无限多的物品
    2. 考虑到精度问题,可以左右取对数
      l o g ( e 1 × e 2 × . . . × e k ) > l o g ( 1 ) = 0 log(e_1 \times e_2 \times ... \times e_k) > log(1) = 0 log(e1×e2×...×ek)>log(1)=0
      即: l o g ( e 1 ) + l o g ( e 2 ) + . . . + l o g ( e k ) > 0 − l o g ( e 1 ) − l o g ( e 2 ) − . . . − l o g ( e k ) < 0 log(e_1) + log(e_2) + ... + log(e_k) > 0 \\ -log(e_1) - log(e_2) - ... - log(e_k) < 0 log(e1)+log(e2)+...+log(ek)>0log(e1)log(e2)...log(ek)<0
      到此为止,题目已经转换成边权为 − l o g ( w c a ) -log(\frac {wc}{a}) log(awc) 的判负环问题
    3. 最后注意:该图可能为 “森林“结构。

    Code

    const int N = 4e3 + 3;
    
    int n, m;
    
    int h[N], net[N], e[N], a[N], c[N], tot;
    void add(int x, int y, int z, int zz)
    {
    	e[++tot] = y;
    	a[tot] = z; c[tot] = zz;
    	net[tot] = h[x];
    	h[x] = tot;
    }
    
    
    double d[N];
    int v[N], vis[N], cnt[N];
    //v标记该点是否在队列中
    //vis标记该点是否已经走过,用来遍历森林结构
    //cnt标记该点的跟新次数,更新次数 >= n 则存在负环
    bool spfa(double w)
    {
    	for (int i = 1; i <= n; i++)
    		d[i] = 1e18, v[i] = 0, vis[i] = 0;
    	
    	for (int i = 1; i <= n; i++)
    	{
    		if (vis[i]) continue;
    		vis[i] = 1;
    		
    		queue<int> q;
    		q.push(i);
    		d[i] = 0; v[i] = 1;
    		cnt[i] = 0;
    		while (sz(q))
    		{
    			int x = q.front(); q.pop();
    			v[x] = 0; 
    			for (int i = h[x]; i; i = net[i])
    			{
    				int y = e[i]; double z = -log(w * c[i] / a[i]);
    				if (d[y] > d[x] + z)
    				{
    					vis[x] = 1;//标记走过的点
    					
    					cnt[y] = cnt[x] + 1;
    					if (cnt[y] >= n) return 0;//发现负环
    
    					d[y] = d[x] + z;
    					if (v[y] == 0) q.push(y), v[y] = 1;
    				}
    			}
    		}
    	}
    
    	return 1;
    }
    
    int main()
    {
    	IOS;
    	cin >> n >> m;
    	for (int i = 1, a, b, c, d; i <= m; i++)
    	{
    		cin >> a >> b >> c >> d;
    		add(b, d, a, c);
    	}
    
    	double l = 0, r = 1;
    	while (r - l > esp)
    	{
    		double mid = (l + r) / 2;
    		if (spfa(mid)) l = mid;
    		else r = mid;
    	}
    
    	cout << fixed << setprecision(10) << r << endl;
    
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
  • 相关阅读:
    STM32 | GPIO口的普通与复用如何配置与用法,本文降从最底层教你如何查看手册运用寄存器来实现GPIO口的配置
    mybatis使用双层<foreach> 循环嵌套
    感测型离子风机在线实时监测
    基于Paddle的手写数字识别模型
    探索游戏公司跨部门合作的项目管理工具选择
    基于模型设计和机载软件
    为什么模板的声明与定义不能分离?
    C语言文件操作(超详细版)
    数字孪生技术解决方案助力智慧核电建设
    商城小程序代客下单程序开发演示
  • 原文地址:https://blog.csdn.net/QQ2530063577/article/details/126081852