POJ3169-Layout

知识点-差分约束

上题目POJ3169

例题

题目描述

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

输入

第1行,3个整数,N,ML,MD

第2至ML+1行,3个整数,A, B, D,其中1 <= A < B <= N. 牛A,B距离最多为D (1 <= D <= 1,000,000)

第ML+2至ML+MD+1行,三个整数,A, B, D, 其中 1 <= A < B <= N. 牛A,B距离最少为D (1 <= D <= 1,000,000)

输出

一个整数

如果在上述条件下,奶牛站不成一排,则输出"-1",如果能站成一排,但是第1头牛~第N头牛的距离无限远,则输出"-2",如果满足条件,并且第1头牛~第N头牛之间存在实际距离,则输出第1头牛~到第N头牛之间的能达到的最远距离。

样例输入

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

样例输出

27

分析

本题求的是最大差,也就是最短路。然而给出的约束条件既有a-b<=k,又有a-b>=k的形式。我们只需要a-b<=k,那么对于a-b>=k,我们可以把它转换成b-a<=-k。

然而貌似有这两个约束条件还不够用!根据题目描述:每两头牛距离大于等于0。我们不难得到第三个约束条件:(i+1)-i>=0,也就是i-(i+1)<=0。

将三个约束条件再一一列出:

a-b<=k

b-a<=-k

i-(i+1)<=0

本题还必须判断有无解以及距离是不是无限大。对于有无解只需要判断负边权环,如果节点入队次数超过总节点数就说明存在负边权环;距离无限大就更好判断不说了。

代码

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
using namespace std; 
struct p{ 
    int to,v,nxt; 
}edge[150015]; 
long long n,cnt,ml,md,a,b,d,dis[150015],c[150015],queue[150015],heads[150015],head,tail; 
bool vis[150015]={0}; 
int addEdge(int u,int v,int val) 
{ 
    edge[++cnt].to=v; 
    edge[cnt].v=val; 
    edge[cnt].nxt=heads[u]; 
    heads[u]=cnt; 
} 
int spfa() 
{ 
    for(int i=1;i<=n;++i) dis[i]=0x7fffffff; 
    dis[1]=0;queue[1]=1;head=0;tail=1;vis[1]=1; 
    while(head<=tail) 
    { 
        int node=queue[++head]; 
        vis[node]=0; 
        for(int i=heads[node];i!=0;i=edge[i].nxt) 
        { 
            int to=edge[i].to,val=edge[i].v; 
            if(dis[to]>dis[node]+val) 
            { 
                dis[to]=dis[node]+val; 
                if(!vis[to]) 
                { 
                    queue[++tail]=to; 
                    vis[to]=1; 
                    if(++c[to]>n)return 1; 
                } 
            } 
        } 
    } 
    return 0; 
} 
int main() 
{ 
    scanf("%d%d%d",&n,&ml,&md); 
    for(int i=1;i<=ml;i++) 
    { 
        scanf("%d%d%d",&a,&b,&d); 
        addEdge(a,b,d); 
    } 
    for(int i=1;i<=md;i++) 
    { 
        scanf("%d%d%d",&a,&b,&d); 
        addEdge(b,a,-d); 
    } 
    for(int i=1;i<n;i++) 
        addEdge(i+1,i,0); 
    if(spfa())printf("-1\n"); 
    else if(dis[n]>=0x7fffffff)printf("-2\n"); 
    else printf("%d\n",dis[n]); 
} 

 

posted on 2017-04-18 14:04  Skype_lorenzo  阅读(111)  评论(0编辑  收藏  举报

导航