[洛谷 P1993]小K的農場 --- 差分約束 + spfa判環
阿新 • • 發佈:2018-11-10
傳送門:洛谷 P1993
題目描述
小 在 裡面建立很多很多的農場,總共 個,以至於他自己都忘記了每個農場中種植作物的具體數量了,他只記得一些含糊的資訊(共 個),以下列三種形式描述:
- 農場 比農場 至少多種植了 個單位的作物,
- 農場 比農場 至多多種植了 個單位的作物,
- 農場 與農場 種植的作物數一樣多。
但是,由於小 的記憶有些偏差,所以他想要知道存不存在一種情況,使得農場的種植作物數量與他記憶中的所有資訊吻合。
分析
本題僅分為兩部分,建圖+判負環
- 建圖 — 差分約束
在一張的圖上邊 ,必定滿足不等式 ,對於本題而言,也有類似的關係:
令 表示農場 的作物數量,則有
-
那麼類似的,將 、 看做節點, 、 看做邊權建圖即可
- 判負環 —
版
由於題目只要求是否可行,那麼就只要判負數就可以了。
版的判斷依據:第二次訪問該節點即存在負環
優化: 陣列可以不用賦初值,直接為 即可。可以減少沒必要的迭代。
注意:圖不一定聯通,要 一遍(不判實測 )
程式碼
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
int n, m;
int to[20005], nxt[20005], val[20005];
int cnt, last[10005];
IL void add(int u, int v, int w)
{
//printf("%d %d %d\n", u, v, w);
to[++cnt] = v; nxt[cnt] = last[u]; val[cnt] = w; last[u] = cnt;
}
bool vis[10005];
int dis[10005];
IL bool dfs_spfa(int u)
{
vis[u] = 1;
for(int i = last[u], v; (v = to[i]); i = nxt[i])
if(dis[u] + val[i] < dis[v])
{
dis[v] = dis[u] + val[i];
if(vis[v] || dfs_spfa(v)) return 1;
}
vis[u] = 0;
return 0;
}
int main()
{
n = read(); m = read();
for(int k, x, y, z; m; --m)
{
k = read(); x = read(); y = read();
if(k != 3) z = read();
if(k == 1) add(x, y, -z); else
if(k == 2) add(y, x, z); else
if(k == 3) { add(x, y, 0); add(y, x, 0); }
}
int flag;
for(int i = 1; i <= n; ++i)
if(!vis[i])
{
flag = dfs_spfa(i);
if(flag) break;
}
printf("%s\n", flag ? "No" : "Yes" );
return 0;
}