【CPLUSOJ】【USACO】【差分约束】排队(layout)

【题目描述】
Robin喜欢将他的奶牛们排成一队。假设他有N头奶牛,编号为1至N。这些奶牛按照编号大小排列,并且由于它们都很想早点吃饭,于是就很可能出现多头奶牛挤在同一位置的情况(也就是说,如果我们认为所有奶牛位于数轴上,那么多头奶牛的位置坐标可能相同)。

因为众所周知的原因,某些奶牛之间互相喜欢,他们希望互相之间的距离至多为一个定值。但某些奶牛之间互相厌恶,他们希望互相之间的距离至少为一个定值。现在给定ML个互相喜爱的奶牛对以及他们之间距离的最大值,MD个互相厌恶的奶牛对以及他们之间距离的最小值。

你的任务是计算在满足以上条件的前提下,帮助Robin计算出编号为1和编号为N的奶牛之间距离的最大可能值。

【输入格式】

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n,ML和DL ;

此后ML行,每行包含三个用空格分开的整数A,B和D,其中A,B满足1<=A<=B<=N。表示编号为A和B的奶牛之间的距离至多为D。

此后MD行,每行包含三个用空格分开的整数A,B和D,其中A,B满足1<=A<=B<=N。表示编号为A和B的奶牛之间的距离至少为D。

【输出格式】

仅包含一个整数。如果不存在任何合法的排队方式,就输出-1。如果编号1和编号N的奶牛间距离可以任意,就输出-2 。否则输出他们之间的最大可能距离。

【输入样例】

4 2 1

1 3 10

2 4 20

2 3 3

【输出样例】

27

【数据范围】

对于40%的数据,N<=100;

对于100%的数据,N<=1000;ML,MD<=10000;D<=1000000。

【来源】
USACO

【解题思路】
经典的差分约束系统,由于要求最大值,根据不等式组解集的求法,符合条件的最大值正是不等号右边的最小值,所以要用最短路。
依题意可以得出两种不等式:
喜欢:B-A<=D
讨厌:B-A>=D
由于要使用最短路,所以统一符号采用小于等于号(根据最短路中的松弛原理d[e] < < <script type="math/tex" id="MathJax-Element-1"><</script>d[s]+val[s,e]移项就可以得到这个结论)
所以把讨厌的不等式变成A-B>= <script type="math/tex" id="MathJax-Element-2">-</script>D
接下来就是建图
把A和B看做图中的节点,权值为D,那么就形成一条有向边。
A→(权值为D)B
以此建图即可
【解题反思】
做的时候卡了很久,最后发现自己的SPFA出队忘记把出队的元素标记为未访问。
【参考程序】

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
long long n,l,h,cost[1001],a,b,c;
bool visit[1001];
struct data
{
    long long e;
    long long v;
};
vector<data> edge[2005];
long long cnt[1001];
void add(int sta,int end,int val)
{
    data tmp;
    tmp.e=end;
    tmp.v=val;
    edge[sta].push_back(tmp);
}
queue<int> que;
void First()
{
    for (int i=1;i<=n;i++) cost[i]=0xfffffff;
    cost[1]=0;
}
bool SPFA()
{
    que.push(1);
    visit[1]=true;
    int f;
    while (!que.empty())
    {
        f=que.front();
        for (int i=0;i<edge[f].size();i++)
        {
            long long end=edge[f][i].e;
            long long val=edge[f][i].v;
            if (cost[end]>cost[f]+val)
            {
                cost[end]=cost[f]+val;
                if (!visit[end])
                {
                    visit[end]=true;
                    que.push(end);
                }
                cnt[end]++;//记录松弛次数 
                if (cnt[end]>=n) return true;//松弛n次就必然出现负环,无解 
            }
        }
        que.pop();
        visit[f]=false;//打SPFA一定要记得写这句。 
    }
    return false;
}
int main()
{
    cin>>n>>l>>h;
    for (int i=1;i<=l;i++)
    {
        cin>>a>>b>>c;
        add(a,b,c);//建图 
    }
    for (int j=1;j<=h;j++)
    {
        cin>>a>>b>>c;
        add(b,a,-c);//建图 
    }
    First();//初始化 
    if (SPFA()) printf("-1");//负环无解 
    else if (cost[n]==0xfffffff) printf("-2");//不连通 
    else cout<<cost[n]; //有解情况 
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值