[洛谷P1993]小K的农场

原题传送门

这道题的实质是差分约束。我们逐个分析。

  • 农场a比农场b至少多种植了c个单位的作物,
  • 农场a比农场b至多多种植了c个单位的作物,
  • 农场a与农场b种植的作物数一样多。

设$a$农场中有$d[a]$个单位植物,$b$农场为$d[b]$,

对于第一点,则满足:$d[a]-d[b] \geq c$,变形下就变成:$d[b]-d[a] \leq -c$。

对于第二点:$d[a]-d[b] \leq c$。

对于第三点:$d[a]=d[b]$,即$d[a]-d[b]=0$,变成不等式就要同时满足$d[a]-d[b] \leq 0$且$d[b]-d[a] \leq 0$。

根据一系列不等式组,即可构图。

对于$d[u]-d[v] \leq w$,将$v$连一条有向边到$u$,权值为$w$。

最后将$0$号结点连向每个结点,权值为$0$。

判断整个图是否有负环即可。

因为如果有负环,算法将会无限制地执行松弛操作,也就是无法满足不等式组成立,也就是输出$"No"$。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define maxx(a, b) a = max(a, b);
 9 #define minn(a, b) a = min(a, b);
10 #define LL long long
11 #define inf (1 << 30)
12 
13 inline int read() {
14     int w = 0, f = 1; char c = getchar();
15     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
16     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
17     return w * f;
18 }
19 
20 const int maxn = 1e4 + 5, maxm = 1e4 + 5;
21 
22 struct Edge {
23     int u, v, w, pre;
24 };
25 
26 queue<int> q;
27 int inq[maxn], cnt[maxn];
28 struct Graph {
29     Edge edges[maxm << 2];
30     int n, m;
31     int G[maxn], dis[maxn];
32     void init(int n) {
33         this->n = n;
34         m = 0;
35         memset(G, 0, sizeof(G));
36     }
37     void AddEdge(int u, int v, int w) {
38         edges[++m] = (Edge){u, v, w, G[u]};
39         G[u] = m;
40     }
41     bool SPFA() {
42         memset(dis, 0x3f, sizeof(dis));
43         memset(cnt, 0, sizeof(cnt));
44         memset(inq, 0, sizeof(inq));
45         //rep(i, 0, n) { q.push(i); inq[i] = 1; dis[i] = 0; }
46         q.push(0), inq[0] = 1, dis[0] = 0;
47         while (!q.empty()) {
48             int u = q.front(); q.pop(); inq[u] = 0;
49             for (int i = G[u]; i; i = edges[i].pre) {
50                 Edge &e = edges[i];
51                 if (dis[e.u] + e.w < dis[e.v]) {
52                     dis[e.v] = dis[e.u] + e.w;
53                     if (!inq[e.v]) {
54                         q.push(e.v); inq[e.v] = 1;
55                         if (++cnt[e.v] > n) return false;
56                     }
57                 }
58             }
59         }
60         return true;
61     }
62 } G;
63 
64 int n, m;
65 
66 int main() {
67     n = read(), m = read();
68     G.init(n);
69 
70     rep(kase, 1, m) {
71         int opt = read();
72         if (opt == 1) {
73             int u = read(), v = read(), w = read();
74             G.AddEdge(u, v, -w);
75         } else
76         if (opt == 2) {
77             int u = read(), v = read(), w = read();
78             G.AddEdge(v, u, w);
79         } else {
80             int u = read(), v = read();
81             G.AddEdge(u, v, 0);
82             G.AddEdge(v, u, 0);
83         }
84     }
85     rep(i, 1, n) G.AddEdge(0, i, 0);
86 
87     if (G.SPFA()) printf("Yes");
88     else printf("No");
89 
90     return 0;
91 }

该做法在本题中会$TLE$,复杂度为$O(nm)$。

下面的方法把$SPFA$改成了深搜的写法,实质类似于将负权边构成图,单独判断是否有环。经验证,比上面快几十倍。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define maxx(a, b) a = max(a, b);
 9 #define minn(a, b) a = min(a, b);
10 #define LL long long
11 #define inf (1 << 30)
12 
13 inline int read() {
14     int w = 0, f = 1; char c = getchar();
15     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
16     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
17     return w * f;
18 }
19 
20 const int maxn = 1e4 + 5, maxm = 1e4 + 5;
21 
22 struct Edge {
23     int u, v, w, pre;
24 };
25 
26 struct Graph {
27     Edge edges[maxm << 1];
28     int n, m;
29     int G[maxn], dis[maxn], vis[maxn];
30     void init(int n) {
31         this->n = n+1;
32         m = 0;
33         memset(G, 0, sizeof(G));
34     }
35     void AddEdge(int u, int v, int w) {
36         edges[++m] = (Edge){u, v, w, G[u]};
37         G[u] = m;
38     }
39     bool spfa(int u) {
40         vis[u] = 1;
41         for (int i = G[u]; i; i = edges[i].pre) {
42             Edge &e = edges[i];
43             if (dis[u] + e.w > dis[e.v]) {
44                 dis[e.v] = dis[u] + e.w;
45                 if (vis[e.v]) return false;
46                 if (!spfa(e.v)) return false;
47             }
48         }
49         vis[u] = 0;
50         return true;
51     }
52 } G;
53 
54 int n, m;
55 
56 int main() {
57     n = read(), m = read();
58     G.init(n);
59 
60     rep(kase, 1, m) {
61         int opt = read();
62         if (opt == 1) {
63             int u = read(), v = read(), w = read();
64             G.AddEdge(u, v, w);
65         } else
66         if (opt == 2) {
67             int u = read(), v = read(), w = read();
68             G.AddEdge(u, v, 0);
69             G.AddEdge(v, u, -w);
70         } else {
71             int u = read(), v = read();
72             G.AddEdge(u, v, 0);
73             G.AddEdge(v, u, 0);
74         }
75     }
76     rep(i, 1, n) G.AddEdge(0, i, 0);
77     memset(G.dis, ~0x3f, sizeof(G.dis));
78     G.dis[0] = 0;
79     if (G.spfa(0)) printf("Yes");
80     else printf("No");
81 
82     return 0;
83 }

 

posted @ 2019-01-27 15:54  AC-Evil  阅读(210)  评论(0编辑  收藏  举报