[POJ3169] Layout

  设第i号牛的位置为d[i]。

  题目相当于给出了三个约束条件:

  1. d[i] <= d[i+1]
  2. d[AL] + DL >= d[BL]
  3. d[AD] + DD <= d[BD]

  恰好可以用最短路模型来解答。因为在这样的问题当中 d[e[i].u]+e[i].w <= d[e[i].v] 刚好和上面的不等式形式相同。这样的问题还有个名字叫做差分约束。

  因此在i 和 i+1 之间建长度为0的边,AL 和 BL之间建立长度为 DL 的边,AD和BD之间建立长度为 -DD 的边(移项可知),对于这个图再跑一遍SPFA,求出d[n]即可。(不能用dijkstra是因为里面有负权边)

  判断负权边的方法是看更新次数是否已经超过了总边数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int INF = 1<<30;
int N,ML,MD;
int AL,BL,DL;
int AD,BD,DD;
int d[1005];
bool inq[1005];
struct Edge
{
    int v,next,w;
}e[20005];
int front[1005];
int cnt = 0;
void AddEdge(int u,int v,int w)
{
    e[++cnt].v = v;
    e[cnt].w = w;
    e[cnt].next = front[u];
    front[u] = cnt;
}
bool flag = false;
void spfa()
{
    queue<int> q;
    for (int i = 1; i <= N; i++) d[i] = INF;
    memset(inq,0,sizeof inq);
    q.push(1);
    inq[1] = 1,d[1] = 0;
    int cntt = 1;
    while(!q.empty())
    {
        cntt++;
        if(cntt > N+ML+MD) 
        {
            flag = true;
            break;
        }
        int xx = q.front();
        q.pop();
        inq[xx] = 0;
        for (int i = front[xx];i;i = e[i].next)
        {
            if(d[e[i].v] > e[i].w + d[xx])
            {
                d[e[i].v] = e[i].w + d[xx];
                if(!inq[e[i].v])
                {
                    inq[e[i].v] = 1;
                    q.push(e[i].v);
                }
            }
        }
        
    }
}
int main()
{
    scanf("%d%d%d",&N,&ML,&MD);
    for (int i = 1; i < N; i++)
    {
        AddEdge(i+1,i,0);
    }
    for (int i = 1; i <= ML; i++)
    {
        scanf("%d%d%d",&AL,&BL,&DL);
        AddEdge(AL,BL,DL);
    }
    for (int i = 1; i <= MD; i++)
    {
        scanf("%d%d%d",&AD,&BD,&DD);
        AddEdge(BD,AD,-DD);
    }
    spfa();
    if(flag) puts("-1");
    else if(d[N] == INF) puts("-2");
    else{
        printf("%d\n",d[N]);
    }
    return 0;
}
显示代码

 

 

posted @ 2018-08-27 21:10  ELU_FOREVER  阅读(107)  评论(0编辑  收藏  举报