洛谷P1993 小K的农场 [差分约束系统]

时间:2024-01-13 21:37:20

  题目传送门

小K的农场

题目描述

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

  • 农场a比农场b至少多种植了c个单位的作物,
  • 农场a比农场b至多多种植了c个单位的作物,
  • 农场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”。

输入输出样例

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

说明

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


  分析:

  差分约束系统的裸题,用来练练。

  三种条件分别可以转换成:

  $1:dis[a]\geq dis[b]+c$

  $2:dis[b]\geq dis[a]-c$

  $3:dis[a]\geq dis[b]+0,dis[b]\geq dis[a]+0$

  其中第三种条件可以放心建边,因为题目本身的要求就只是查看是否有负环就行了,只要无负环就输出$Yes$,有负环就输出$No$。因为是判断负环,所以用$dfs$版$SPFA$(一开始打了个$BFS$版,然后死活要$WA$一个点。。。。)。

  Code:

//It is made by HolseLee on 21st Aug 2018
//Luogu.org P1993
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<vector>
#define Max(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
using namespace std; const int N=1e4+;
int n,m,dis[N],tim[N];
bool vis[N],flag;
struct Node{
int to,val;
Node(int x=,int y=){
to=x,val=y;
}
};
vector<Node>e[N];
queue<int>team; inline int read()
{
char ch=getchar();int num=;bool flag=false;
while(ch<''||ch>''){if(ch=='-')flag=true;ch=getchar();}
while(ch>=''&&ch<=''){num=num*+ch-'';ch=getchar();}
return flag?-num:num;
} void spfa(int u)
{
vis[u]=true;
int v;
for(int i=;i<e[u].size();++i){
v=e[u][i].to;
if(dis[v]>dis[u]+e[u][i].val){
if(vis[v])flag=false;return;
dis[v]=dis[u]+e[u][i].val;
spfa(v);
}
}
vis[u]=false;
} int main()
{
n=read();m=read();
int x,y,z,v;
for(int i=;i<=m;++i){
x=read(),y=read(),z=read();
switch(x){
case :v=read();e[z].push_back(Node(y,v));break;
case :v=read();e[y].push_back(Node(z,-v));break;
case :e[y].push_back(Node(z,));e[z].push_back(Node(y,));break;
}
}
flag=true;
for(int i=;i<=n;++i){
dis[i]=;
spfa(i);
if(!flag)break;
}
if(flag)printf("Yes\n");
else printf("No\n");
return ;
}