SCU-4527 NightMare2 (Dijkstra变形)

原题地址:http://acm.scu.edu.cn/soj/problem.action?id=4527

思路:方法有点难想,做完加深了dijkstra的理解.

我们知道原来的dijkstra在进行松弛的时候,是只对边的长度关系进行判断的,,但是这题中多了一种限制,限制了每条边的宝藏数量,所以我们考虑在松弛的时候加上宝藏的关系,满足一定的数量才能进行松弛.所以,我们只需要二分宝藏数量,然后跑 l o g n 次的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;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81452745