洛谷 1993 小 K 的农场

41 篇文章 0 订阅

题目描述 Description

小 K 在 Minecraft 里面建立很多很多的农场,总共 n 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 m 个),以下列三种形式描述:
1. 农场 a 比农场 b 至少多种植了 c 个单位的作物。
2. 农场 a 比农场 b 至多多种植了 c 个单位的作物。
3. 农场 a 与农场 b 种植的作物数一样多。
但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种
植作物数量与他记忆中的所有信息吻合。

输入格式:

第一行包括两个整数 n 和 m,分别表示农场数目和小 K 记忆中的信息数目。
接下来 m 行:
如果每行的第一个数是 1,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至少多种植
了 c 个单位的作物。
如果每行的第一个数是 2,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至多多种植
了 c 个单位的作物。如果每行的第一个数是 3,家下来有 2 个整数 a,b,表示农场 a 终止的
数量和 b 一样多。

输出格式:

如果存在某种情况与小 K 的记忆吻合,输出“Yes”,否则输出“No”。

输入样例:

3 3
3 1 2
1 1 3 1
2 2 3 2

输出样例:

Yes

数据范围

对于 100% 的数据保证:1 ≤ n,m,a,b,c ≤ 10000。

差分约束裸题,对于第一种情况,建一条 a 到 b 权值为 -c 的边,第二种情况,建一条 b 到 a 权值为 c 的边,第三种情况,建一条 a 和 b 间 权值为 0 的双向边,然后跑最短路判负环或者跑最长路判正环就好,数据好像卡spfa,裸spfa会 T 几个点,要加个 SLF 优化,至于代码里注掉的那两行qwq,那两行要慎用233,如果 SLF 都过不了的话,去掉 SLF 加那两行说不定会有奇效(真 · 黑科技)233。

#include<iostream>
#include<cstdio>
#include<deque>
#include<cstring>
using namespace std;
const int size = 200010;
int head[size],next[size],dist[size];
bool use[size];
int tot = 1,n,m;
struct dc
{
    int t,d;
}l[size];
deque < int > q;
inline void build(int f,int t,int d)
{
    l[tot].t = t;
    l[tot].d = d;
    next[tot] = head[f];
    head[f] = tot ++;
}
int tim[size];
inline bool spfa(int s)
{
    for(register int i = 1 ; i <= n ; i ++)
        dist[i] = 214748364;
    dist[s] = 0;
    use[s] = 1;
    q.push_back(s);
    while(!q.empty())
    {
        int f = q.front();
        q.pop_front();
        use[f] = 0;
        for(register int i = head[f] ; i ; i = next[i])
        {
            int t = l[i].t;
            if(dist[t] > dist[f] + l[i].d)
            {
                dist[t] = dist[f] + l[i].d;
                if(!use[t])
                {
                    tim[t] ++;
                    if(tim[t] > n)
                        return false;
                    use[t] = 1;
                    if(!q.empty())
                    {
                        if(dist[t] < dist[q.front()])
                            q.push_front(t);
    //                  else if(t > q.front())
    //                      q.push_front(t);
                        else
                            q.push_back(t);
                    }
                    else
                        q.push_back(t);
                }
            }
        }
    }
    return true;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(register int i = 1 ; i <= m ; i ++)
    {
        int ins;
        scanf("%d",&ins);
        int f,t,d;
        if(ins == 1)
        {
            scanf("%d%d%d",&f,&t,&d);
            build(f,t,-d);
        }
        else if(ins == 2)
        {
            scanf("%d%d%d",&f,&t,&d);
            build(t,f,d);
        }
        else
        {
            scanf("%d%d",&f,&t);
            build(f,t,0);
            build(t,f,0);
        }
    } 
    for(register int i = 1 ; i <= n ; i ++)
        build(0,i,0);
    if(spfa(0))
        puts("Yes");
    else
        puts("No");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值