POJ 3169 图论 差分约束系统

来源:互联网 发布:华南理工大学 知乎 编辑:程序博客网 时间:2024/06/06 00:09

题目链接:http://poj.org/problem?id=3169
题意:
一个牛舍里有按序号排列的N头牛(可以多头牛在统一位置),有一些牛的关系比较好,他们希望彼此不超过一定的距离。当然也有些牛关系不好,他们希望彼此超过一定的距离。
有ML对牛的关系比较好,并给出每对牛的所不超过的距离D;同样,有MD对牛的关系不好,并给出每对牛的所超过的距离D。
问是否有满足这样的安排方案满足所有牛的要求。若不存在,输出-1;若存在,但是牛1和牛N之间的距离可以任意大,输出-2;否则,输出牛1和牛N之间的最大距离。

类型:
差分约束系统

分析:
差分约束系统脱胎于最短路。最短路中有一个关系:d[from] + cost >= d[to]。
而我们观察这道题,有三个约束条件:
1.牛按序号排列:d[i]<=d[i+1] 转化为 d[i+1]+ 0>=d[i]
2.友好牛:d[BL]-d[AL]<=DL 转化为 d[AL]+DL>=d[BL]
3.仇视牛 : d[BD]-d[AD]>=DD 转化为 d[BD]+(-DD)>=d[AD]
根据这种约束,我们可以建立不同牛的边,最后求最短路。
因为(-DD)的存在,即负边,我们不能采用Dijkstra算法,这里使用bellmann-ford 算法

时间复杂度&&优化:
O( N(N+ML+MD) )
代码:

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<queue>#include<stack>#include<math.h>#include<vector>#include<algorithm>#include<iostream>using namespace std;const int MAX_N = 100005;const int MAX_M = 5005;const int MAX_R = 5005;const int INF = 1000000007;const int mod = 1000000007;int n,r1,r2;int d[MAX_N];///最小距离struct edge{    int u,v,cost;};vector<edge> ed;bool find_negative_loop(){///返回ture,说明存在负圈    memset(d,0,sizeof(d));    for(int i=0;i<n;i++){        for(int j=0;j<ed.size();j++){            edge e=ed[j];            if(d[e.u]+e.cost<d[e.v]){                d[e.v]=d[e.u]+e.cost;                if(i==n-1)return true;            }        }    }    return false;}int main(){    while(cin>>n>>r1>>r2&&n){        //下面三个for循环,即是根据三个约束条件的建边        for(int i=0;i<n-1;i++){            edge tmp;            tmp.u=i+1;tmp.v=i;tmp.cost=0;            ed.push_back(tmp);        }        for(int i=0;i<r1;i++){            edge tmp;            scanf("%d%d%d",&tmp.u,&tmp.v,&tmp.cost);            tmp.u--;tmp.v--;//从0存储            ed.push_back(tmp);        }        for(int i=0;i<r2;i++){            edge tmp;            scanf("%d%d%d",&tmp.v,&tmp.u,&tmp.cost);            tmp.u--;tmp.v--;//从0存储            tmp.cost=-tmp.cost;            ed.push_back(tmp);        }//        for(int i=0;i<ed.size();i++){//            edge e=ed[i];//            cout<<e.u+1<<" "<<e.v+1<<" "<<e.cost<<endl;//        }        ///存在负圈则无解        if(find_negative_loop()){            cout<<-1<<endl;            continue;        }        ///求最短路        for(int i=0;i<n;i++){            d[i]=INF;        }d[0]=0;        while(true){            bool update=false;            for(int i=0;i<ed.size();i++){                edge e=ed[i];                if(d[e.u]!=INF&&d[e.u]+e.cost<d[e.v]){                    d[e.v]=d[e.u]+e.cost;                    update=true;                }            }            if(!update)break;        }        if(d[n-1]==INF){cout<<-2<<endl;continue;}        else{cout<<d[n-1]<<endl;}    }    return 0;}
0 0