P1993 小 K 的农场

小 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 1n,m,a,b,c5×103

#include
using namespace std;
#define pii pair<int,int>
#define il inline
#define re register
#define FOR(i,n,s) for(int i=(s);i<=(n);i++) 
const int MAXN=1e8+5;
vector<pii> edges[MAXN];
int dis[MAXN];
int n,m,s;
int cnt[MAXN];
bool inQueue[MAXN];
queue<int> q;
//SPFA
il void add(int u,int v,int w)
{
	edges[u].emplace_back(v,w);
}
il bool SPFA(int s)
{
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	q.push(s);
	inQueue[s]=true;
	while(!q.empty())
	{
		int x=q.front();q.pop();
		inQueue[x]=false;
		for(auto edge:edges[x])
		{
			if(dis[edge.first]<=dis[x]+edge.second) continue;
			dis[edge.first]=dis[x]+edge.second;
			if(!inQueue[edge.first])
			{
				q.push(edge.first);
				inQueue[edge.first]=true;
				cnt[edge.first]++;
				if(cnt[edge.first]>=n+1) return false;
			}
		}
	}
	return true;
}
//标准的SPFA模板

int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=m;i++) 
	{
		int u,v,w,opt;
		cin>>opt>>u>>v;
		if(opt<3) cin>>w;
		if(opt==1) add(u,v,-w);
		if(opt==2) add(v,u,w);
		if(opt==3) {add(u,v,0);add(v,u,0);} 
	}//建图
	for(int i=0;i<=n;i++) add(0,i,0);//建立超级源点
	if(!SPFA(0)) cout<<"No";
    else cout<<"Yes";
	return 0;
}

PS:

题目其中 m 条信息有如下三种形式:
1. a i − a j > = c 1.a_i-a_j>=c 1.aiaj>=c
2. a i − a j < = c 2.a_i-a_j<=c 2.aiaj<=c
3. a i = a j 3.a_i=a_j 3.ai=aj
我们可以把这三种形式转化为:
1. a j < = a i − c 1.a_j<=a_i-c 1.aj<=aic
2. a i < = a j + c 2.a_i<=a_j+c 2.ai<=aj+c
3. a i − a j = 0 3.a_i-a_j=0 3.aiaj=0
看到这三个不等式我们很容易就会想到这道题用查分约束解决
根据这三个不等式,我们可以依次建边:
1. ( j , i , − c ) 1.(j,i,-c) 1.(j,i,c)
2. ( i , j , c ) 2.(i,j,c) 2.(i,j,c)
3. ( i , j , 0 ) ( j , i , 0 ) 3.(i,j,0)(j,i,0) 3.(i,j,0)(j,i,0)
然后我们跑一遍SPFA即可(更多关于模板的细节可看前几篇题解)

你可能感兴趣的:(图论,算法,c++,KISS)