BZOJ 3436: 小K的农场 差分约束
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=3436
题解:
裸的差分约束:
1、a>=b+c -> b<=a-c -> d[v]<=d[u]+w -> 建一条边从a到b,权值为-c
2、a<=b+c -> d[v]<=d[u]+w -> 建一条边从b到a,权值为c
3、a==b -> d[v]<=d[u]+0&&d[u]<=d[v]+0 建一条边从a到b,权值为0。建一条边从b到a,权值为0.
建完图,从原点0到各点连边,权值都为0,跑最短路。
代码:
#include<iostream> #include<cstdio> #include<vector> #include<cstring> #include<queue> #define mp make_pair #define X first #define Y second using namespace std; const int maxn = 10000 + 10; vector<pair<int,int> > G[maxn]; int n, m; int inq[maxn], d[maxn], cnt[maxn]; bool spfa(int s) { memset(inq, 0, sizeof(inq)); memset(d, 0x7f, sizeof(d)); memset(cnt, 0, sizeof(cnt)); queue<int> Q; d[s] = 0, inq[s] = 1, Q.push(s); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].X,w=G[u][i].Y; if (d[v] > d[u] + w) { d[v] = d[u] + w; if (!inq[v]) { inq[v] = 1, Q.push(v); if (++cnt[v] > n + 1) return false; } } } } return true; } void init() { for (int i = 0; i <= n; i++) G[i].clear(); } int main() { while (scanf("%d%d", &n, &m) == 2 && n) { init(); for (int i = 1; i <= n; i++) { G[0].push_back(mp(i, 0)); } for (int i = 0; i < m; i++) { int cmd, a, b,c; scanf("%d", &cmd); if (cmd == 1) { scanf("%d%d%d", &a, &b, &c); G[a].push_back(mp(b, -c)); } else if (cmd == 2) { scanf("%d%d%d", &a, &b, &c); G[b].push_back(mp(a, c)); } else { scanf("%d%d", &a, &b); G[a].push_back(mp(b, 0)); G[b].push_back(mp(a, 0)); } } bool ans = spfa(0); if (ans) puts("Yes"); else puts("No"); } return 0; } /* 3 3 3 1 2 1 1 3 1 2 2 3 2 */