好题分享
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;
}