bzoj3436: 小K的農場(差分約束系統)
阿新 • • 發佈:2019-01-06
題目描述:小K是個特麼喜歡玩MC的孩紙。。。
小K在MC裡面建立很多很多的農場,總共n個,以至於他自己都忘記了每個農場中種植作物的具體數量了,他只記得
一些含糊的資訊(共m個),以下列三種形式描述:農場a比農場b至少多種植了c個單位的作物,農場a比農場b至多
多種植了c個單位的作物,農場a與農場b種植的作物數一樣多。但是,由於小K的記憶有些偏差,所以他想要知道存
不存在一種情況,使得農場的種植作物數量與他記憶中的所有資訊吻合。
輸入格式:第一行包括兩個整數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
輸出格式:如果存在某種情況與小K的記憶吻合,輸出”Yes”,否則輸出”No”。
輸入樣例:
3 3
3 1 2
1 1 3 1
2 2 3 2
輸出樣例:
Yes
解析:又是一道差分約束的題。。。
對於\(a-b≥c\),連一條w[b,a]=c的邊。
對於\(a-b≤c\),連一條w[a,b]=-c的邊。
對於\(a=b\),連兩條w[a,b]=0,w[b,a]=0的邊。
最後跑一遍最長路即可。
注意要用dfs代替spfa,不然會超時。
#include<cstdio> using namespace std; const int maxn = 10005; const int maxm = 30005; int n, m, vis[maxn], dis[maxn]; int nxt[maxm], hed[maxm], to[maxm], val[maxm], cnt; int read(void) { char c; while (c = getchar(), c < '0' || c >'9'); int x = c - '0'; while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x; } void add(int x, int y, int v) { nxt[++ cnt] = hed[x]; hed[x] = cnt; to[cnt] = y; val[cnt] = v; } int dfs(int u) { vis[u] = 1; for (int i = hed[u]; i ; i = nxt[i]) { int v = to[i]; if (dis[v] < dis[u] + val[i]) { dis[v] = dis[u] + val[i]; if (vis[v] || !dfs(v)) return 0; } } vis[u] = 0; return 1; } int main() { n = read(); m = read(); for (int i = 1; i <= m; ++ i) { int opt = read(); if (opt == 1) { int x = read(), y = read(), v = read(); add(y, x, v); } else if (opt == 2) { int x = read(), y = read(), v = read(); add(x, y, -v); } else { int x = read(), y = read(); add(x, y, 0); add(y, x, 0); } } for (int i = 1; i <= n; ++ i) add(0, i, 0); for (int i = 1; i <= n; ++ i) dis[i] = -2e9; if (dfs(0)) printf("Yes"); else printf("No"); return 0; }