zoukankan      html  css  js  c++  java
  • POJ3662 SPFA//二分 + 双端队列最短路

    https://cn.vjudge.net/problem/12427/origin

    题意:求1到N第K + 1大条边权最小的路径

    首先想到dp递推,dp[x][y]表示到x这个点经过y条免费边的最小值。

    直接借助SPFA递推即可

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 1010;
    const int maxm = 20010;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,tmp,K; 
    struct Edge{
        int v,w,next;
    }edge[maxm * 2];
    int head[maxn],tot;
    void init(){
        Mem(head,-1);
        tot = 0;
    }
    void add(int u,int v,int w){
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    bool vis[maxn][maxn];
    int dp[maxn][maxn]; // 到达i经过p条免费边最大值
    struct Node{
        int p,x,cost;
        Node(int x = 0,int p = 0,int cost = 0):x(x),p(p),cost(cost) {}
    };
    void SPFA(){
        queue<Node>Q;
        Q.push(Node(1,0,0));
        while(!Q.empty()){
            Node u = Q.front(); Q.pop();
            vis[u.x][u.p] = 0;
            for(int i = head[u.x];~i;i = edge[i].next){
                int v = edge[i].v;
                if(dp[v][u.p] > max(dp[u.x][u.p],edge[i].w)){
                    dp[v][u.p] = max(dp[u.x][u.p],edge[i].w);
                    if(!vis[v][u.p]){
                        vis[v][u.p] = 1;
                        Q.push(Node(v,u.p,dp[v][u.p]));
                    }
                }
                if(u.p < K && dp[v][u.p + 1] > dp[u.x][u.p]){
                    dp[v][u.p + 1] = dp[u.x][u.p];
                    if(!vis[v][u.p + 1]){
                        vis[v][u.p + 1] = 1;
                        Q.push(Node(v,u.p + 1,dp[v][u.p + 1]));
                    }
                }
            }
        }
    }
    int main()
    {
        scanf("%d%d%d",&N,&M,&K);
        init();
        For(i,1,M){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w); add(v,u,w);
        }
        memset(dp,0x3f,sizeof(dp));
        dp[1][0] = 0;
        SPFA();
        int ans = INF;
        _For(i,K,0){
            ans = min(ans,dp[N][i]);
        }
        if(ans == INF) Pri(-1);
        else Pri(ans);
        #ifdef VSCode
        system("pause");
        #endif
        return 0;
    }
    SPFA

    第二个思想是二分答案,将大于这个答案的边权变为0,小于这个答案的边权变为1,直接跑1到N的最短路进行check

    对于01图的最短路有一个技巧是用双端队列,类似BFS的方法跑,将权值为1的边进入的点加到队尾,权值0到达的点加到队尾即可。

    #include <map>
    #include <set>
    #include <deque>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 1010;
    const int maxm = 20010;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,tmp,K; 
    struct Edge{
        int v,w,next;
    }edge[maxm * 2];
    int head[maxn],tot;
    void init(){
        Mem(head,-1);
        tot = 0;
    }
    void add(int u,int v,int w){
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    bool vis[maxn];
    int dis[maxn];
    bool check(int x){
        deque<int>Q;
        Q.push_back(1);
        Mem(vis,0);
        Mem(dis,0x3f);
        dis[1] = 0;vis[1] = 1;
        while(!Q.empty()){
            int u = Q.front(); Q.pop_front();
            if(u == N) return dis[u] <= K;
            for(int i = head[u]; ~i; i = edge[i].next){
                int v = edge[i].v; int w = edge[i].w;
                if(w <= x){
                    dis[v] = min(dis[v],dis[u]);
                    if(!vis[v]) Q.push_front(v);
                } 
                else{
                    dis[v] = min(dis[v],1 + dis[u]);
                    if(!vis[v]) Q.push_back(v);
                }
                vis[v] = 1; 
            }
        }
        return false;
    }
    int solve(int r){
        int l = 0;
        int ans = -1;
        while(l <= r){
            int m = (l + r) >> 1;
            if(check(m)){
                ans = m;
                r = m - 1;
            }else{
                l = m + 1;
            }
        }
        return ans;
    }
    int main()
    {
        int MAX = 0;
        scanf("%d%d%d",&N,&M,&K);
        init();
        For(i,1,M){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            MAX = max(MAX,w);
            add(u,v,w); add(v,u,w);
        }
        Pri(solve(MAX));
        #ifdef VSCode
        system("pause");
        #endif
        return 0;
    }
  • 相关阅读:
    用简单的方法解决问题
    记一次调试
    工作笔记还是蛮有用
    35岁往上做什么
    2013年个人总结
    一个C++宏定义与枚举定义重复的编译错误
    动态库的麻烦之处
    谈谈软件项目的dependency
    创建pathing jar
    谈谈patch strategy
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9677805.html
Copyright © 2011-2022 走看看