1. 程式人生 > >[BZOJ 3436] 小K的農場

[BZOJ 3436] 小K的農場

[題目連結]

         https://www.lydsy.com/JudgeOnline/problem.php?id=3436

[演算法]

        不難發現 , 題目中的約束條件都可以寫成

        1. Da - Db >= c

        2. Da - Db <= c

        3. Da = Db

        考慮使用差分約束系統

        第一種約束條件 :將b向a連一條權值為c的有向邊

        第二種約束條件 :將a向b連一條權值為-c的有向邊

        第三種約束條件 :   將a向b連一條權值為0的有向邊 , 將b向a連一條權值為0的有向邊

        然後 , 我們只需判斷該圖中是否存在正環 , SPFA判定即可 , 注意使用SPFA的DFS形式

        時間複雜度 : O(N ^ 2)

[程式碼]

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
const int inf = 2e9;

struct edge
{
        int to , w , nxt;
} e[MAXN << 1];

int tot , n , m;
bool inq[MAXN];
int dist[MAXN] , head[MAXN];

template <typename T> inline void
chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void addedge(int u , int v , int w) { ++tot; e[tot] = (edge){v , w , head[u]}; head[u] = tot; } inline bool spfa(int u) { inq[u] = true; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to , w = e[i].w; if (dist[u] + w > dist[v]) { dist[v] = dist[u] + w; if (inq[v]) return true; if (spfa(v)) return true; } } inq[u] = false; return false; } int main() { read(n); read(m); for (int i = 1; i <= m; i++) { int type; read(type); if (type == 1) { int a , b , c; read(a); read(b); read(c); // d[a] - d[b] >= c addedge(b , a , c); } else if (type == 2) { int a , b , c; read(a); read(b); read(c); // d[a] - d[b] <= c addedge(a , b , -c); } else { int a , b; read(a); read(b); // d[a] - d[b] >= 0 , d[b] - d[a] >= 0 addedge(b , a , 0); addedge(a , b , 0); } } for (int i = 1; i <= n; i++) { dist[i] = -inf; addedge(0 , i , 0); } if (!spfa(0)) printf("Yes\n"); else printf("No\n"); return 0; }