洛谷P1993 小k的农场

题目

差分约束+判正环

差分约束:

给定几个形如\(a_i-b_i<=c_i\)\(a_i-b_i>=c_i\)的不等式。

一般问题都会问\(a_i-b_j\)的最小值或最大值,或者是否所有条件都满足。

松弛操作\(dis[now]-dis[to]<e[i].len\)与上文的不等式十分相似,然后考虑最小值,最大值和是否满足等问题转化为图论问题。为了方便,先选择将不等式都转为一个符号(习惯因人而异)

小于号: 都转移到小于号后,假设如下不等式b-a<=c这句话如果转化到图中,意思是一个点x到另一个点y当前的边是c,x到y的最短路不可能比c还大,就是还可能会有更短的最短路连接x,y,此时需要向图中加边(x->y=c);加入原题要问b-a的最大值,则转化到图中就是x到y的最小值因为最大值要所有路径都要满足。如果有条件不满足则说明会存在两点间的最小值会不断更新,即图中存在负环,或者会存在两点间根本不相连,此时他们之间的最大值可以取无数解

大于号类似。

#include <bits/stdc++.h>
#define N 10001011
using namespace std;
struct edg {
	int to, nex, len;
}e[N];
int lin[N], dis[N], cnt, n, m;
inline void add(int f, int t, int l)//添加一组松弛关系
{
	e[++cnt].len = l;
	e[cnt].to = t;
	e[cnt].nex = lin[f];
	lin[f] = cnt;
}
int vis[N], b[N], flag;
void dfs(int now)
{
	b[now] = 1;
	for (int i = lin[now]; i; i = e[i].nex)
	{
		int to = e[i].to;
		if (dis[now] + e[i].len > dis[to])//当前节点还没有被找到过,或者已经被找到过但是又重新到了这个点上。 
		{
			if (b[to])
				printf("No"), exit(0);
			dis[to] = dis[now] + e[i].len;
			dfs(to);
		}
	}
	b[now] = 0;
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++)
	{
		int flag, a, b, c;
		scanf("%d", &flag);
		if (flag == 1)//a - b > c
		{
			scanf("%d%d%d", &a, &b, &c);
			add(b, a, c);//a比b至少大c 
		}
		if (flag == 2)//a-b<c
		{
			scanf("%d%d%d", &a, &b, &c);
			add(a, b, -c);//b比a至少小c,意思就是a比b至多大c 
		}
		if (flag == 3)
		{
			scanf("%d%d", &a, &b);
			add(b, a, 0), add(a, b, 0);//a比b至少大0,b比a至少大0 
		} 
	}
	for (int i = 1; i <= n; i++)
		add(0, i, 0), dis[i] = -2147483647;
	dfs(0);
	printf("Yes");
	return 0;
}	
posted @ 2019-11-07 17:02  刘文尧  阅读(112)  评论(0编辑  收藏