POJ 3169 Layout 差分约束/Bellman-Ford

POJ 3169 Layout

博客搬新家,以后就是基本只在自己的独立博客进行更新,欢迎访问。http://zihengoi.cn

题目链接:

  题目链接:POJ 3169 Layout

题目大意:

   n 头牛编号为1 n ,按照编号的顺序排成一列,每两头牛的之间的距离>=0。这些牛的距离存在着一些约束关系:
  1.有 ml u,v,w 的约束关系,表示牛 [u] 和牛 [v] 之间的距离必须 <=w
  2.有 md u,v,w 的约束关系,表示牛 [u] 和牛 [v] 之间的距离必须 >=w
  问如果这 n 头无法排成队伍,则输出1,如果牛 [1] 和牛 [n] 的距离可以无限远,则输出 2 ,否则则输出牛 [1] 和牛 [n] 之间的最大距离。

解题思路:

  • 对于任意i号奶牛, 1<=i<N ,在距离上应该满足: D[i+1]D[i]>=0 ,即 D[i+1]>=D[i] ;
  • 对于每个好感的描述 (ijk) ,假设 i<=j ,体现到距离上的要求就是: D[j]D[i]<=k ,即 D[j]<=D[i]+k ;
  • 对于每个反感的描述 (ijk) ,假设 i<=j ,体现到距离上的要求就是: D[j]D[i]>=k ,即 D[i]<=D[j]+(k)

1.对于差分不等式, ab<=c ,建一条 b a 的权值为 c 的边,该边的权值即为 a,b, 间的最大值,对于不等式 ab>=c ,建一条 b a 的权值为c的边,该边的权值即为 a,b, 间的最小值。
2.如果检测到负环,那么无解。
3.如果 d[N] 没有更新,那么可以是任意解。

复杂度分析:

时间复杂度 : O(n(ml+md))
空间复杂度 : O(n)

AC代码:

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<cstdio>

using namespace std;

const int INF = 0x7fffffff;
const int maxn = 20010;

struct Edge {
int from, to, dist;
};

struct BellmanFord {
    int n,m;
    vector<Edge> edges;
    vector<int > G[maxn];
    bool inq[maxn];
    int d[maxn];
    int cnt[maxn];

    void init(int n) {
        this -> n = n;
        for(int i = 0; i < n; i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from, int to, int dist) {
        edges.push_back((Edge){from, to, dist});
        m = edges.size();
        G[from].push_back(m-1);
    }

    bool Bellman_Ford() {
        queue<int>Q;
        memset(inq, 0, sizeof(inq));
        memset(cnt, 0, sizeof(cnt));
        for(int i = 1; i < n; i++) d[i] = INF;
        d[0] = 0;
        inq[0] = true;
        Q.push(0);
        while(!Q.empty()){
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for(int i = 0; i < G[u].size(); i++) {
                Edge& e = edges[G[u][i]];
                if(d[u] < INF && d[e.to] > d[u] + e.dist){
                    d[e.to] = d[u] + e.dist;
                    if(!inq[e.to]) {
                        Q.push(e.to);
                        inq[e.to] = true;
                        if(++cnt[e.to] > n) return true;
                    }
                }
            }
        }
        return false;
    }
}slove;


int main()
{
    int n,ml,md;
    while(scanf("%d%d%d",&n,&ml,&md) != EOF){
        slove.init(n);
        int from,to,dist;
        for(int i = 0; i < ml; i++) {
            scanf("%d%d%d",&from,&to,&dist);
            slove.AddEdge(from-1,to-1,dist);
        }
        for(int i = 0; i < md; i++) {
            scanf("%d%d%d",&from,&to,&dist);
            slove.AddEdge(to-1,from-1, -dist);
        }
        bool ans = slove.Bellman_Ford();
        if(ans) printf("-1\n");
        else if(slove.d[n-1] == INF) printf("-2\n");
        else printf("%d\n",slove.d[n-1]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值