小 K 的农场
题目描述
小 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,接下来有三个整数 a , b , c a,b,c a,b,c,表示农场 a a a 比农场 b b b 至少多种植了 c c c 个单位的作物;
- 如果每行的第一个数是 2 2 2,接下来有三个整数 a , b , c a,b,c a,b,c,表示农场 a a a 比农场 b b b 至多多种植了 c c c 个单位的作物;
- 如果每行的第一个数是 3 3 3,接下来有两个整数 a , b a,b a,b,表示农场 a a a 种植的的数量和 b b b 一样多。
输出格式
如果存在某种情况与小 K 的记忆吻合,输出 Yes
,否则输出 No
。
样例 #1
样例输入 #1
3 3
3 1 2
1 1 3 1
2 2 3 2
样例输出 #1
Yes
提示
对于 100 % 100\% 100% 的数据,保证 1 ≤ n , m , a , b , c ≤ 5 × 1 0 3 1 \le n,m,a,b,c \le 5 \times 10^3 1≤n,m,a,b,c≤5×103。
前置芝士:差分约束
大致思路
整理题意后,可得 m 条信息有如下三种形式:
a i − a j ≥ c a_{i}-a_{j}\ge c ai−aj≥c
a i − a j ≤ c a_{i}-a_{j}\le c ai−aj≤c
a i = a j a_{i}=a_{j} ai=aj
可以将式子转化为下面的形式:
a j ≤ a i − c a_{j}\le a_{i}-c aj≤ai−c
a i ≤ a j + c a_{i}\le a_{j}+c ai≤aj+c
a i ≤ a j + 0 a_{i}\le a_{j}+0 ai≤aj+0和 a j ≤ a i + 0 a_{j}\le a_{i}+0 aj≤ai+0a
在 SPFA 中如下方式更新 dis 数组。
for(int i=0;i<ve[x].size();i++){
int xv=ve[x][i].v,xw=ve[x][i].w;
if(dis[xv]>dis[x]+xw){
dis[xv]=dis[x]+xw;
if(vis[xv]==0){
q.push(xv);
vis[xv]=1;
}
}
}
也就是 d i s i = min { d i s j + < j , i > } dis_{i}=\min\left\{dis_{j}+<j,i>\right\} disi=min{disj+<j,i>}
于是在遇到 a i ≤ a j + c a_{i}\le a_{j}+c ai≤aj+c
这样的不等式时,我们可以从 j 到 i 建一条边权为 b 的 有向边。
为了避免图不连通的情况,我们需要一个超级源点 n+1,与点 i 之间连一条边权为 0 的边。
那么怎么判断有没有解呢?
那就是判断 负环。
那么又怎么判断负环呢?
只要用一个数组来统计每个点的入队次数,如果某个点的入队次数 ≥ n + 1 \ge n+1 ≥n+1 则说明无解,输出 No,否则输出 Yes
AC CODE
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+234;
#define int long long int
int n,m,ans=0,cnt=0;
int dis[N],cont[N];
bool vis[N];
struct node{
int v,w;
};
vector<node> ve[N];
void SPFA(){
memset(dis,0x7f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(cont,0,sizeof(cont));
queue<int> q;
dis[n+1]=0;
vis[n+1]=1;
cont[n+1]++;
q.push(n+1);
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=0;i<ve[x].size();i++){
int xv=ve[x][i].v,xw=ve[x][i].w;
if(dis[xv]>dis[x]+xw){
dis[xv]=dis[x]+xw;
if(vis[xv]==0){
q.push(xv);
cont[xv]++;
vis[xv]=1;
if(cont[xv]>n+1){
cout<<"No"<<endl;
return;
}
}
}
}
}
cout<<"Yes"<<endl;
return;
}
signed main(){
node tmp;
cin>>n>>m;
for(int i=1;i<=m;i++){
int op,a,b,c;
//cnt++;
cin>>op>>a>>b;
if(op==1){//b-a<=-c
cin>>c;
tmp.v=b,tmp.w=-c;
ve[a].push_back(tmp);
}
else if(op==2){//a-b<=c
cin>>c;
tmp.v=a,tmp.w=c;
ve[b].push_back(tmp);
}
else if(op==3){//a-b<=0&&a-b>=0
tmp.v=a;tmp.w=0;
ve[b].push_back(tmp);
tmp.v=b;
ve[a].push_back(tmp);
}
}
for(int i=1;i<=n;i++){
tmp.v=i;tmp.w=0;
ve[n+1].push_back(tmp);
}
SPFA();
return 0;
}