poj 1364 King 差分约束
这题再次对差分约束的超源点有了新的理解。
设d[i] = a[1] + …+a[i],根据题意有:
d[si + ni] – d[si-1] >= k + 1
d[si+ni] – d[si-1] <= k - 1 即 d[si-1] – d[si+ni] >= 1 – k
通过求最长路来判断图中是否存在正环。
这题可以通过加超源点,或者不加,加超源点不好想
使用bellman算法,这个不需要加超源点,但要注意,每条边要松弛n次,而不是n-1次,因为图的顶点是从0~n的,开始没注意,WA好多次。
使用spfa算法,这里如果不添加超源点的话,要先把所有点都入队,再进行松弛,这样保证,每个点都得到检查。
而添加超源点,加设添加超源点a[n+1], a[n+1]是无穷小的数,即-INF, 它与前面的a[1] ~ a[n] 之和也是无穷小的,即s[n+1] = –INF。从而s[n+1] – s[i] <= 0不等式成立,即有 s[i] – s[n+1] >= 0, (i = 1,2,..,n), 再以n+1为源点开始搜索,这样得到的解,除了满足题设的要求外,还满足了不等式s[i] – s[n+1] >= 0, 因为a[n+1]任我们假设的,因此添加了这个不等式对题目没有任何影响。
#include<iostream> #include <queue> using namespace std; const int MAX = 1000; const int INF = 1000000000; struct Node { int v; int cost; int next; }; Node node[MAX]; int d[MAX]; int adj[MAX]; bool in_q[MAX]; int cnt[MAX]; int size; int n, m; void add_edge(int u, int v, int cost) { node[size].v = v; node[size].cost = cost; node[size].next = adj[u]; adj[u] = size++; } bool spfa() { queue<int> Q; memset(cnt, 0, sizeof(cnt)); memset(in_q, false, sizeof(in_q)); for (int i = 0; i <= n; i++) d[i] = -INF; //添加一个为n+1的超源点 for (int i = 0; i <= n; i++) add_edge(n+1, i, 0); //d[n+1] = 0; 这句不能加,因为d[n+1]是为-INF,是无限小的数 in_q[n+1] = true; Q.push(n+1); int u, v, w; while (!Q.empty()) { u = Q.front(); Q.pop(); in_q[u] = false; for (int i = adj[u]; i != -1; i = node[i].next) { v = node[i].v; w = node[i].cost; if (d[v] < d[u] + w) { d[v] = d[u] + w; if (!in_q[v]) { in_q[v] = true; Q.push(v); if (++cnt[v] > n) return false; } } } } return true; } bool bellman_ford() { int v, w; bool isfinish; //这里需要松弛n次,而不是n-1次,不然会WA //因为这里的顶点数是从0~n共n+1个, 0也是有意义的。 for (int i = 1; i <= n; i++) { isfinish = true; for (int u = 0; u <= n; u++) for (int k = adj[u]; k != -1; k = node[k].next) { v = node[k].v; w = node[k].cost; if (d[u] < d[v] + w) { d[u] = d[v] + w; isfinish = false; } } if (isfinish) break; } for (int u = 0; u <= n; u++) for (int k = adj[u]; k != -1; k = node[k].next) { v = node[k].v; w = node[k].cost; if (d[u] < d[v] + w) return false; } return true; } int main() { char c[10]; int a, b, w; while (scanf("%d", &n)) { if (n == 0) break; scanf("%d", &m); for (int i = 0; i <= n+1; i++) adj[i] = -1; size = 0; for (int i = 0; i < m; i++) { scanf("%d %d %s %d", &a, &b, c, &w); if (strcmp(c, "gt") == 0) add_edge(a-1, a+b, w+1); else add_edge(a+b, a-1, 1-w); } if (spfa()) printf("lamentable kingdom\n"); else printf("successful conspiracy\n"); } return 0; }