zoukankan      html  css  js  c++  java
  • POJ 3169 Layout(差分约束+最短路)题解

    题意:有一串数字1~n,按顺序排序,给两种要求,一是给定u,v保证pos[v] - pos[u] <= w;二是给定u,v保证pos[v] - pos[u] >= w。求pos[n] - pos[1]最大,若无解输出-1,无穷多解输出-2。

    思路:光看题目好像和最短路无关,其实这里用到了spfa的松弛操作来保证所给出的两种要求。若pos[v] - pos[u] >= w,则pos[v] +(- w) >=  pos[u],也就是pos[v] +(- w) < pos[u]时进行松弛,建一条边v->u,权值-w,这就和spfa中的那一步对应上了,于是转化为了最短路。另一种条件也是如此操作。无解的情况应为出现了负环;无穷多解的情况为1和n没有条件约束,也就是1没有路通向n。

    参考:

    夜深人静写算法(四) - 差分约束

    代码:

    #include<cstdio>
    #include<set>
    #include<cmath>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<sstream>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn = 1000+5;
    const int INF = 0x3f3f3f3f;
    struct Edge{
        int v,cost;
        Edge(int _v = 0,int _cost = 0):v(_v),cost(_cost){}
    };
    vector<Edge> G[maxn];
    bool vis[maxn];
    int cnt[maxn];
    int dist[maxn];
    void addEdge(int u,int v,int cost){
        G[u].push_back(Edge(v,cost));
    }
    bool spfa(int st,int n){
        memset(vis,false,sizeof(vis));
        memset(dist,INF,sizeof(dist));
        vis[st] = true;
        dist[st] = 0;
        queue<int> q;
        while(!q.empty()) q.pop();
        q.push(st);
        memset(cnt,0,sizeof(cnt));
        cnt[st] = 1;
        while(!q.empty()){
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int i = 0;i < G[u].size();i++){
                int v = G[u][i].v;
                if(dist[v] > dist[u] + G[u][i].cost){
                    dist[v] = dist[u] + G[u][i].cost;
                    if(!vis[v]){
                        vis[v] = true;
                        q.push(v);
                        if(++cnt[v] > n) return false;
                    }
                }
            }
        }
        return true;
    }
    int main(){
        int n,ml,md;
        scanf("%d%d%d",&n,&ml,&md);
        for(int i = 0;i <= n;i++) G[i].clear();
        for(int i = 1;i <= ml;i++){ //at most -> v - u <= w ->  v <= w + u
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addEdge(u,v,w);
        }
        for(int i = 1;i <= md;i++){ //at least -> v - u >= w -> u <= -w + v
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addEdge(v,u,-w);
        }
        bool cannot = spfa(1,n);
        if(!cannot){
            printf("-1
    ");
        }
        else{
            if(dist[n] == INF){
                printf("-2
    ");
            }
            else{
                printf("%d
    ",dist[n]);
            }
        }
        return 0;
    }
  • 相关阅读:
    【leetcode】 61. 旋转链表
    【leetcode】 55 跳跃游戏
    【leetcode 53】 最大子序和
    【leetcode】不同路径
    【leetcode】692. 前K个高频单词
    vue a标签使用@click
    函数式接口的使用
    【转】MyBatis中的collection两种使用方法
    xaf--homepage
    Windows10--设置鼠标自带光圈效果
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9474663.html
Copyright © 2011-2022 走看看