【CODEVS 1242】布局 SPFA + 差分约束

传送门:CODEVS
题目描述 Description
当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。FJ有N(2<=N<=1000)头奶牛,编号从1到N,沿一条直线站着等候喂食。奶牛排在队伍中的顺序和它们的编号是相同的。因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。即使说,如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。

一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数L。另一方面,一些奶牛相互间非常反感,它们希望两者间的距离不小于一个给定的数D。给出ML条关于两头奶牛间有好感的描述,再给出MD条关于两头奶牛间存有反感的描述。(1<=ML,MD<=10000,1<=L,D<=1000000)

你的工作是:如果不存在满足要求的方案,输出-1;如果1号奶牛和N号

奶牛间的距离可以任意大,输出-2;否则,计算出在满足所有要求的情况下,1号奶牛和N号奶牛间可能的最大距离。

输入描述 Input Description
Line 1: Three space-separated integers: N, ML, and MD.

Lines 2..ML+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at most D (1 <= D <= 1,000,000) apart.

Lines ML+2..ML+MD+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at least D (1 <= D <= 1,000,000) apart.

输出描述 Output Description
Line 1: A single integer. If no line-up is possible, output -1. If cows 1 and N can be arbitrarily far apart, output -2. Otherwise output the greatest possible distance between cows 1 and N.

样例输入 Sample Input

4 2 1
1 3 10
2 4 20
2 3 3

样例输出 Sample Output
27

题解:
这个题目看描述就是一系列的不等式,所以很自然的想到是差分约束系统。嗯,什么是差分约束系统呢?
简单的说就是将一系列不等式转化为一条条边然后跑最短路。
那么怎么转化呢?
若问题是像本题一样一个点到各个点的最大距离

可以将题目中的条件写成如下形式

xj−xi≤D     //两个点距离小于D
xj−xi≥D     //两个点距离大于D

我们对于第一个不等式作如下转化

    xj − xi ≤ D     
=> xj ≤ xi + D 

发现它和最短路问题中的三角不等式是一致的:

//D是S到V的最短路 C是U到V的边权
D(s,v)≤D(s,u)+C(u,v),(u,v)∈E

于是我们可以将

xj ≤ xi + D 这个不等式转化为
由i到j的一条长度为D的边
xj − D ≥ xi 这个不等式转化为
由j到i的一条长度为-D的边

详细证明请看:chrt
然后由1作为起点跑SPFA(必须为SPFA因为dij在有负边的时候不能使用)
对于题目:若有负权环则输出-1,若无法到达点N则输出-2,否则直接输出1~N的距离即可
判断负环
有一种较优秀的方法:对于每一个点记录从起点到这个点最短路径包含的边的条数。
若边的条数大于N,易证这个图有负环。
代码

/*
作者:WZH
题目:p1242 布局
*/
#include <iostream>
#include <cstdio>
#include <queue>

const int MAXN = 1005,MAXX = 100000,INF = 10e8;

using namespace std;

int N,ML,MD,e = 1,head[MAXN],sum[MAXN],d[MAXN];
bool inq[MAXN];

queue<int>q; 

struct node{
    int v,c,next;
}edge[MAXX];

inline int read(){
    int x = 0;char ch = getchar();
    while(ch < '0' || '9' < ch) {ch = getchar();}
    while('0' <= ch&&ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}
    return x;
}

inline void addedge(int u,int v,int c){
    edge[e] = (node){v,c,head[u]};head[u] = e++;
}

inline void init(){
    N = read();ML = read();MD = read();

    int u,v,c;

    for(int i = 1;i <= ML;i++){
        u = read();v = read();c = read();
        addedge(u,v,c);
    }

    for(int i = 1;i <= MD;i++){
        u = read();v = read();c = read();
        addedge(v,u,-c);
    }
} 

inline int spfa()
{
    for(int i = 1;i <= N;i++) d[i] = INF;

    q.push(1);inq[1] = true;
    d[1] = 0;sum[1] = 1;

    while(!q.empty()){
        int u = q.front();q.pop();inq[u] = false;

        for(int i = head[u];i;i = edge[i].next){
            int v = edge[i].v,c = edge[i].c;
            if(d[v] > d[u] + c){
                d[v] = d[u] + c;
                sum[v] = sum[u] + 1;
                if(!inq[v]) {q.push(v);inq[v] = true;}
                if(sum[v] > N) return -1;
            }
        }
    }

    if(d[N] == INF) return -2;
    return d[N];
}

int main()
{
    init();

    printf("%d",spfa());

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值