好题分享:luogu P5837 [USACO19DEC]Milk Pumping G

好题分享

luogu P5837 [USACO19DEC]Milk Pumping G

读完题后,人们会自然想到,这就是最短路板子题,只不过判断的条件改一下而已。但是自信一交,发现只得 20 p t s 20pts 20pts(特指 d i j dij dij堆优化)。此时,我们调试后发现,本题与正常的最短路有点不一样,那就是:一个点在被更新后,还能被再次更新!!!

也就是说,我们代码中 v i s vis vis数组的标记是毫无作用的。为什么会出现这种情况呢??因为本题中的“最短路”与两个值有关:价值(V)和花费(C)。但是,我们堆里面用于比较的,却只有他们的比值。

意思是:对于某一个点来说,它的 V ÷ C V \div C V÷C的值可能较大,就导致它会更早的去更新其他点。但是此时,被他更新的点不一定是最优解·。

这就是本题的坑点所在。具体见 c o d e : code: code:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1005;
typedef double db;
int n, m;
struct my_str {
	int to, nxt;
	db val, cost;
}edge[maxn * 2];
int head[maxn], tot = 0;
db dis[maxn];
bool vis[maxn];
struct my_str1 {
	int loc;
	db value, costcost, road;
	friend bool operator <(my_str1 a, my_str1 b) {
		return a.road > b.road;
	}
};
priority_queue < my_str1 > qq;

struct picture {
	inline void add(int x, int y, int z, int c) {
		edge[++ tot].nxt = head[x];
		edge[tot].to = y;
		edge[tot].cost = 1.0 * c;
		edge[tot].val = 1.0 * z;
		head[x] = tot;
	}
	
	void Dij() {
		dis[1] = 0;
		my_str1 F;
		F.loc = 1;
		F.costcost = 0.0;
		F.value = 0x7f7f7f7f;
		F.road = 0x7f7f7f7f;
		qq.push(F);
		while(!qq.empty()) {
			my_str1 Top = qq.top();
			qq.pop();
			int Loc = Top.loc;
			db Val = Top.value;
			db Cost = Top.costcost;
			db Road = Top.road;
			vis[Loc] = 1;
			for(int i = head[Loc]; i != -1; i = edge[i].nxt) {
				int To = edge[i].to;
				db CC = edge[i].cost;
				db VV = edge[i].val;
				if(min(VV, Val) / (CC + Cost) > dis[To]) {
					my_str1 mark = Top;
					mark.loc = To;
					mark.value = min(VV, Val);
					mark.costcost = CC + Cost;
					mark.road = mark.value / mark.costcost;
					dis[To] = mark.road;
					qq.push(mark);
				}
			}
		}
	}
}pic;

struct node {
	inline int read() {
		int x = 0, f = 1;
		char ch = getchar();
		while(!isdigit(ch)) {
			if(ch == '-') f = -1;
			ch = getchar();
		}
		while(isdigit(ch)) {
			x = (x << 1) + (x << 3) + (ch ^ 48);
			ch = getchar();
		}
		return x * f;
	}
	
	void work() {
		n = node::read(), m = node::read();
		memset(head, -1, sizeof head);
		for(int i = 1; i <= m; i ++) {
			int x = node::read(), y = node::read(), z = node::read(), c = node::read();
			pic.add(x, y, c, z);
			pic.add(y, x, c, z);
		}
		pic.Dij();
		printf("%.0lf", floor(dis[n] * 1000000.0));
	}
}code;

int main() {
	code.work();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值