Description
背景 小K是个特么喜欢玩MC的孩纸。。。 描述
小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得
一些含糊的信息(共m个),以下列三种形式描述:农场a比农场b至少多种植了c个单位的作物,农场a比农场b至多
多种植了c个单位的作物,农场a与农场b种植的作物数一样多。但是,由于小K的记忆有些偏差,所以他想要知道存
不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
Input
第一行包括两个整数n和m,分别表示农场数目和小K记忆中的信息的数目接下来m行:如果每行的第一个数是1,接
下来有三个整数a,b,c,表示农场a比农场b至少多种植了c个单位的作物如果每行第一个数是2,接下来有三个整数a
,b,c,表示农场a比农场b至多多种植了c个单位的作物如果每行第一个数是3,接下来有两个整数a,b,表示农场a
种植的数量与b一样。1<=n,m,a,b,c<=10000
Output
如果存在某种情况与小K的记忆吻合,输出”Yes”,否则输出”No”
Sample Input
3 3
3 1 2
1 1 3 1
2 2 3 2
Sample Output
Yes
HINT
样例解释
三个农场种植的数量可以为(2,2,1)
题解
差分约束一眼题
直接设d[i]为第i个农场种植的作物数
输入x,y,c(c第三种操作可以去掉)
第一种操作 d[y]≥d[x]-c 那么x~y连一条-c的边
第二种操作 d[x]≥d[y]+c 那么y~x连一条c的边
第三种操作 d[x]≥d[y] 且 d[y]≥d[x] 那么x~y和y~x都要一条权为0的边
跑最长路即可,最短路的话吧上面改一下也可以跑。。
记住判环的时候一定要break掉while
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
int x,y,c,next;
}a[51000];int len,last[51000];
void ins(int x,int y,int c)
{
len++;
a[len].x=x;a[len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
}
int d[51000];bool v[51000];
int sta[51000],top,ru[51000];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
len=0;memset(last,0,sizeof(last));
for(int i=1;i<=m;i++)
{
int x,y,c,op;
scanf("%d%d%d",&op,&x,&y);
if(op==1 || op==2)scanf("%d",&c);
if(op==1)ins(x,y,-c);
else if(op==2)ins(y,x,c);
else ins(y,x,0),ins(x,y,0);
}
memset(d,0,sizeof(d));
memset(ru,0,sizeof(ru));
top=0;memset(v,true,sizeof(v));
for(int i=1;i<=n;i++)sta[++top]=i,ru[i]++;
bool bk=false;
while(top)
{
int x=sta[top--];
v[x]=false;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(d[y]<d[x]+a[k].c)
{
d[y]=d[x]+a[k].c;
ru[y]++;
if(ru[y]>=n){bk=true;break;}
if(v[y]==false)
{
v[y]=true;
sta[++top]=y;
}
}
}
if(bk==true)break;//这里一定要break,因为上面那个break只是跳出if的。。
}
if(bk==false)printf("Yes\n");
else printf("No\n");
return 0;
}