差分约束:排队布局

原题链接:https://www.acwing.com/problem/content/1172/

需要满足三个差分约束条件:
假设左边的点是a,右边的点是b.
一些奶牛相互间存有好感,它们
希望两者之间的距离不超过一个给定的数 L。
b - a <= L;
一些奶牛相互间非常反感,它们希望两者间
的距离不小于一个给定的数 D。
b - a >= D;
还有一个条件b >= a

1 每头奶牛按编号排序 i+1 → i w = 0
  <=> x[i] ≤ x[i+1]
2 两者之间的距离不超过一个给定的数L
  x[b]-x[a] ≤ L        a → b w = L
  x[b] ≤ x[a] + L
3 两者之间的距离不小于一个给定的数D
  x[b]-x[a] ≥ D        
  x[a] ≤ x[b]-D        b → a w = -D


给的条件有限,所以只能求这些点之间的相对关系,所以题中也就
只问了我们相对关系。

问题1:
因为没有一个点可以无条件到所有点,
所以建超级源点0 从0向
假定所有x[i] ≤ x[0] + 0  从而可以从0向x[i]连一条长度为0的边

为什么需要建立超级源点:建立超级原点是为了判断
是否有负环,这样可以以所有点为起点跑一遍spfa,如果
不建立超级远点那就得跑n次spfa()

1 如果没有负环-有解
2 如果有负环-无解

问题2:
直接把所有点i加入队列 == 创建超级源点0
点1和点n距离是否可以无限大?

则可以把点1固定在一个位置上(选0位置)x[1] = 0,判断x[n]是否可以无限大
/*
    需要满足三个差分约束条件:
    假设左边的点是a,右边的点是b.
    一些奶牛相互间存有好感,它们
    希望两者之间的距离不超过一个给定的数 L。
    b - a <= L;
    一些奶牛相互间非常反感,它们希望两者间
    的距离不小于一个给定的数 D。
    b - a >= D;
    还有一个条件b >= a
    
    1 每头奶牛按编号排序 i+1 → i w = 0
      <=> x[i] ≤ x[i+1]
    2 两者之间的距离不超过一个给定的数L
      x[b]-x[a] ≤ L        a → b w = L
      x[b] ≤ x[a] + L
    3 两者之间的距离不小于一个给定的数D
      x[b]-x[a] ≥ D        
      x[a] ≤ x[b]-D        b → a w = -D

    
    给的条件有限,所以只能求这些点之间的相对关系,所以题中也就
    只问了我们相对关系。
    
    问题1:
    因为没有一个点可以无条件到所有点,
    所以建超级源点0 从0向
    假定所有x[i] ≤ x[0] + 0  从而可以从0向x[i]连一条长度为0的边
    
    为什么需要建立超级源点:建立超级原点是为了判断
    是否有负环,这样可以以所有点为起点跑一遍spfa,如果
    不建立超级远点那就得跑n次spfa()
    
    1 如果没有负环-有解
    2 如果有负环-无解
    
    问题2:
    直接把所有点i加入队列 == 创建超级源点0
    点1和点n距离是否可以无限大?
    
    则可以把点1固定在一个位置上(选0位置)x[1] = 0,判断x[n]是否可以无限大
    
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010, M = 10000 + 10000 + 1000 + 10, INF = 0x3f3f3f3f;

int n, m1, m2;
int h[N], e[M], w[M], ne[M], idx;
int dist[N];
int q[N], cnt[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

bool spfa(int size)
{
    // 每次做spfa记得清空数组
    int hh = 0, tt = 0;
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);
    memset(cnt, 0, sizeof cnt);

    // 用超级源点的时候,把所有的点dist设为0,然后加到队列中
    // 不用超级源点的时候,只需要加1号点就行,求1到n的最长路。
    for (int i = 1; i <= size; i ++ )
    {
        q[tt ++ ] = i;
        dist[i] = 0;
        st[i] = true;
    }

    while (hh != tt)
    {
        int t = q[hh ++ ];
        if (hh == N) hh = 0;
        st[t] = false;

        for (int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                cnt[j] = cnt[t] + 1;
                if (cnt[j] >= n) return true;
                if (!st[j])
                {
                    q[tt ++ ] = j;
                    if (tt == N) tt = 0;
                    st[j] = true;
                }
            }
        }
    }

    return false;
}

int main()
{
    scanf("%d%d%d", &n, &m1, &m2);
    memset(h, -1, sizeof h);

    for (int i = 1; i < n; i ++ ) add(i + 1, i, 0);
    while (m1 -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        if (a > b) swap(a, b);
        add(a, b, c);
    }
    while (m2 -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        if (a > b) swap(a, b);
        add(b, a, -c);
    }

    if (spfa(n)) puts("-1");
    else
    {
        spfa(1);
        if (dist[n] == INF) puts("-2");
        else printf("%d\n", dist[n]);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值