POJ 3169 Layout(初遇差分约束系统)

题目链接:http://poj.org/problem?id=3169

题意: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]之间的最大距离。

这是自己第一道差分约束题,居然这种线性规划还能转化成图论最短路模型解决,实在666啊。

对于差分约束问题我转载了一篇某大牛的文章,说的很详细http://blog.csdn.net/kalilili/article/details/43484765

现在来感受一下这种模型转换的认知,首先单源最短路模型符合差分约束的不等式  d(v) - d(u)<= w(u, v) ,所以找到一组不等式的解就等价于求解dis数组的过程,设定一个源点src后,就把dis[src]=0,用各种最短路算法最终把dis数组从无穷大,松弛到满足差分约束不等式为止,所以可以得出这个结论: 对于这种有一个未知数定死(dis[src]=0)的差分约束系统,通过最短路径算法求出来的一组解当中,所有未知数都达到最大值。

用相同的思路求最长路的时候把dis数组初始化成负无穷,那么设定一个源点(也就是其中一个解是定值0)之后算出来的解有未知数都达到最小值

所以对于本题来说首先先把差分约束系统找到,试图用两个未知数相减的不等式来表示牛之间距离的关系,所以可以把牛的位置用坐标表示,设一个坐标原点,这个原点一定在1号牛的左边,所以牛的位置间的不等关系为:X(Bl)-X(Al)<=E(A,B)=Dl     X(Ad)-X(Bd)<=E(B,A)= -Dd,而且必须把牛按编号顺序排成一排所以又有:X(i)-X(i+1)<=E(i+1,i)=0.然后题目让你求1牛到N牛的最大距离,也就是max(X(N)-X(1))。所以把1号牛的解X(1)定死,通过最短路径算法求出来的一组解当中,所有未知数都达到最大值,所以此时X(N)-X(1)为最大值,所以可以设1号牛左边某一固定距离的位置为源点,初始化dis[1]=a,然后最短路算完,得到答案dis[N]-dis[1],

所以设a的值为0当然最好(只要是定值都可以)。

代码实现:

//	268K	172MS
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define inf 0x7fffffff
using namespace std;
int n,ml,md,flag;
int u[20100],v[20100],w[20100];
int dis[1100];
void bellman()
{
    fill(dis,dis+n+1,inf);
    dis[1]=0;
    for(int i=1;i<n;i++){
        for(int j=2;j<=n;j++){
            if(dis[j]!=inf) dis[j-1]=min(dis[j-1],dis[j]);
        }
        for(int j=1;j<=ml+md;j++){
            if(dis[u[j] ]!=inf) dis[v[j] ]=min(dis[v[j] ],dis[u[j] ]+w[j]);
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&ml,&md);
    for(int i=1;i<=ml;i++) scanf("%d%d%d",&u[i],&v[i],&w[i]);
    for(int i=ml+1;i<=ml+md;i++) {
        scanf("%d%d%d",&v[i],&u[i],&w[i]);
        w[i]*=-1;
    }
    bellman();
    for(int i=1;i<=ml+md;i++)
        if(dis[u[i]]!=inf&&dis[v[i]]>dis[u[i] ]+w[i]) flag=1;
    if(flag) printf("-1\n");
    else if(dis[n]==inf) printf("-2\n");
    else printf("%d\n",dis[n]);
    return 0;
}
此时到这里就把这题解出来了,下面是弱者对于细节的纠结。。。大神就可以忽略啦

由于这题对多种情况都有可能涉及到:负权环,或者不强连通(dis[n]==inf),或者源点与负全环也不连通(这个时候按题意应该输出-1而不是-2)

如果考虑到这些可以hack很多一些ac的代码了(包括我这个),比如源点与负全环不连通,再多一轮循环检测是否有负全环也无济于事,因为我用了“dis[u[i]]!=inf”如果是一般的检测负权环题目可以把inf设小一点,然后把我那个if条件删掉,照样可以判断出负权环,但是这题还要判不连通也就是(dis[n]==inf),所以要保持inf绝对最大值,不能参与松弛过程,所以两者不能兼得,用bellman只能再用一次bellman单独判与源点不相连的负权环。这样就显得有点笨拙。

当然在正常的SPFA中,也检测不了与源点不相连的负权环。但是这里可以有个小技巧,在SPFA使用之前把图上每个点提前入队,再执行算法,检测如果有一个点入队超过了n次那么就有负全环,而且这个时候照样没把inf参与其中,既可以判连通也可以判整个分离图的负权环。

你可能感兴趣的:(POJ 3169 Layout(初遇差分约束系统))