1. 程式人生 > >BZOJ 3436: 小K的農場 差分約束

BZOJ 3436: 小K的農場 差分約束

head 忘記 target 三種 %d ref 就是 ont push

3436: 小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

Sample Output

Yes

思路:

  看題意顯然是差分約束系統,我們對1這種操作連邊 y x z 代表y 比 x 少 z 對2這種連邊x y -z 代表x比y少-z (就是多z) 對第三種連 x y 0 和 y x 0.然後跑一遍最長路判環即可

代碼如下:

技術分享圖片
#include <cstdio>
#include <algorithm>
#include 
<iostream> #include <deque> #include <cstdlib> using namespace std; const int N = 23123; int head[N], to[N], nxt[N], val[N], _; void add(int x, int y, int z) { to[++_] = y; nxt [_] = head[x]; head[x] = _; val [_] = z; } int vis[N], tot[N], f[N], viss[N]; deque
<int> q; int n, m; void spfa(int s) { viss[s]=0; q.push_back(s); while(!q.empty()) { int u = q.front(); q.pop_front(); vis[u] = 0; viss[u] = 1; tot[u]++; if(tot[u]>n) { puts("No"); exit(0); } for(int i=head[u];i;i=nxt[i]) { if(f[to[i]]<f[u]+val[i]) { f[to[i]]=f[u]+val[i]; if(!vis[to[i]]) { if(f[to[i]]>f[q.front()]) q.push_front(to[i]); else q.push_back(to[i]); vis[to[i]]=1; } } } } } int main() { scanf("%d%d", &n, &m); for(int i=1;i<=m;i++) { int opt; scanf("%d", &opt); if(opt==1) { int x, y, z; scanf("%d%d%d", &x, &y, &z); add(y, x, z); } else if(opt==2) { int x, y, z; scanf("%d%d%d", &x, &y, &z); add(x, y, -z); } else { int x, y; scanf("%d%d", &x, &y); add(x, y, 0); add(y, x, 0); } } for(int i=1;i<=n;i++) if(!viss[i])spfa(i); //for(int i=1;i<=n;i++) printf("%d\n", f[i]); puts("Yes"); }
View Code

BZOJ 3436: 小K的農場 差分約束