【BZOJ3436】小K的农场
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
3 1 2
1 1 3 1
2 2 3 2
Sample Output
Yes
样例解释
三个农场种植的数量可以为(2,2,1)
样例解释
三个农场种植的数量可以为(2,2,1)
题解:裸的差分约束
a≥b+c -> b≤a-c
a≤b+c -> a≤b+c
a=b -> a≤b,b≤a
然后连边判负环
#include <cstdio> #include <iostream> #include <cstring> #include <queue> using namespace std; const int maxn=10010; int n,m,cnt; int to[maxn<<1],next[maxn<<1],head[maxn],val[maxn<<1],dis[maxn],inq[maxn],len[maxn]; queue<int> q; void add(int a,int b,int c) { to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++; } int main() { scanf("%d%d",&n,&m); int i,a,b,c,d,u; memset(head,-1,sizeof(head)); for(i=1;i<=m;i++) { scanf("%d%d%d",&d,&a,&b); switch(d) { case 1:scanf("%d",&c),add(a,b,-c); break; case 2:scanf("%d",&c),add(b,a,c); break; case 3:add(a,b,0),add(b,a,0); break; } } for(i=1;i<=n;i++) q.push(i),inq[i]=1,len[i]=1; while(!q.empty()) { u=q.front(),q.pop(),inq[u]=0; for(i=head[u];i!=-1;i=next[i]) { if(dis[to[i]]>dis[u]+val[i]) { dis[to[i]]=dis[u]+val[i]; len[to[i]]=len[u]+1; if(len[to[i]]>n) { printf("No"); return 0; } if(!inq[to[i]]) inq[to[i]]=1,q.push(to[i]); } } } printf("Yes"); return 0; }