[Luogu P1993] 小K的农场

12 篇文章 0 订阅
1 篇文章 0 订阅
洛谷传送门

题目描述

小K在MC里面建立很多很多的农场,总共 n n n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 m m m个),以下列三种形式描述:

  • 农场 a a a比农场 b b b至少多种植了 c c c个单位的作物,
  • 农场 a a a比农场 b b b至多多种植了 c c c个单位的作物,
  • 农场 a a a与农场 b b b种植的作物数一样多。

但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

输入输出格式

输入格式:

第一行包括两个整数 n n n m m m,分别表示农场数目和小 K 记忆中的信息数目。

接下来 m m m 行:

如果每行的第一个数是 1 1 1,接下来有 3 3 3 个整数 a , b , c a,b,c a,b,c,表示农场 a a a 比农场 b b b 至少多种植了 c c c 个单位的作物。

如果每行的第一个数是 2 2 2,接下来有 3 个整数 a , b , c a,b,c a,b,c,表示农场 a 比农场 b 至多多种植了 c c c 个单位的作物

如果每行的第一个数是 3 3 3,接下来有 2 2 2 个整数 a , b a,b a,b,表示农场 a 种植的的数量和 b b b 一样多。

输出格式:

如果存在某种情况与小 K 的记忆吻合,输出 Y e s Yes Yes,否则输出 N o No No

输入输出样例

输入样例#1:
3 3
3 1 2
1 1 3 1
2 2 3 2
输出样例#1:
Yes

说明

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

解题分析

差分约束板题。

对于 1 1 1操作, 转化为 d i s [ a ] ≥ d i s [ b ] + c dis[a]\ge dis[b]+c dis[a]dis[b]+c, 从 b b b a a a连一条长度为 c c c的边。

对于 2 2 2操作, 转化为 d i s [ b ] ≥ d i s [ a ] − c dis[b]\ge dis[a]-c dis[b]dis[a]c, 从 a a a b b b连一条长度为 − c -c c的边。

对于 3 3 3操作, a 、 b a、b ab互相连长度为 0 0 0的边。

为了遍历每个联通块, 从 0 0 0向每个点连长度为 0 0 0的边即可, 最后跑一边 S P F A SPFA SPFA求最长路, 看是否有正环。

代码如下:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define R register
#define INF 100000000
#define IN inline
#define W while
#define gc getchar()
#define MX 10050
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
int head[MX], dis[MX];
int dot, line, cnt;
struct Edge {int to, len, nex;} edge[MX << 2];
IN void add(R int from, R int to, R int len)
{edge[++cnt] = {to, len, head[from]}, head[from] = cnt;}
bool vis[MX];
bool SPFA(R int now)
{
    vis[now] = true;
    for (R int i = head[now]; i; i = edge[i].nex)
    {
        if(dis[edge[i].to] < dis[now] + edge[i].len)
        {
            dis[edge[i].to] = dis[now] + edge[i].len;
            if(vis[edge[i].to]) return false;
            if(!SPFA(edge[i].to)) return false;
        }
    }
    vis[now] = false;
    return true;
}
int main(void)
{
    int typ, a, b, c;
    in(dot), in(line);
    for (R int i = 1; i <= line; ++i)
    {
        in(typ); in(a), in(b);
        if(typ == 1) {in(c); add(b, a, c);}
        else if(typ == 2) {in(c); add(a, b, -c);}
        else add(a, b, 0), add(b, a, 0);
    }
    for (R int i = 1; i <= dot; ++i) add(0, i, 0), dis[i] = -INF; dis[0] = 0;
    if(SPFA(0)) puts("Yes"); else puts("No");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值