原题地址:http://acm.scu.edu.cn/soj/problem.action?id=4527
思路:方法有点难想,做完加深了dijkstra的理解.
我们知道原来的dijkstra在进行松弛的时候,是只对边的长度关系进行判断的,,但是这题中多了一种限制,限制了每条边的宝藏数量,所以我们考虑在松弛的时候加上宝藏的关系,满足一定的数量才能进行松弛.所以,我们只需要二分宝藏数量,然后跑 次的dijkstra就行了.
ac代码:
#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e4 + 5;
int t, n, m, k;
struct edge {
int v, cap, dis, nxt; //dis是时间,cap是财宝数量
bool operator <(const edge &a)const {
return dis > a.dis;
}
edge() {}
edge(int v, int dis): v(v), dis(dis) {}
} e[100005];
int tot, head[10005];
void add_edge(int u, int v, int cap, int dis) {
e[tot].v = v;
e[tot].cap = cap;
e[tot].dis = dis;
e[tot].nxt = head[u];
head[u] = tot++;
}
int vis[maxn];
int dis[maxn];
int dij(int mid) {
CLR(dis, 0x3f);
CLR(vis, 0);
priority_queue<edge>q;
q.push(edge(1, 0));
dis[1]=0;
while(!q.empty()) {
int u = q.top().v;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].v;
if(!vis[v] && dis[v] > dis[u] + e[i].dis && mid <= e[i].cap) {
dis[v] = dis[u] + e[i].dis;
q.push(edge(v, dis[v]));
}
}
}
return dis[n] <= k;
}
int main() {
scanf("%d", &t);
while(t--) {
tot = 0;
CLR(head, -1);
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= m; i++) {
int u, v, cap, dis;
scanf("%d%d%d%d", &u, &v, &cap, &dis);
add_edge(u, v, cap, dis);
add_edge(v, u, cap, dis);
}
int left = 0;
int right = INF;
while(left <= right) {
int mid = (left + right) / 2;
if(dij(mid)) left = mid + 1;
else right = mid - 1;
}
if(right!=-1)printf("%d\n", right);
else printf("Poor RunningPhoton!\n");
}
return 0;
}