做的第一个差分约束的题。读完题后一脸茫然,不会建图。看了算法导论,其实这是
一个建立<= 差分约束系统的过程。
设s[x] = 从0 到x 的所有在集合中的数的个数,则ai到bi的个数即S[bi] - S[ai-1]。
因此有:
(1) S[bi] - S[ai-1] >= ci。
又根据s[x]本身的性质,后面的一定不比前面的小,后面的最多比前面多一,有:
(2) s[i + 1] - s[i] >= 0
(3) s[i + 1] - s[i] <= 1
根据这三个约束条件建图,使图中每一组边,均满足:
S[ai - 1] <= S[bi] - ci
S[i] <= S[i - 1] + 1
S[i - 1] <= S[i]
建完图,用Bellman-Ford来迭代就OK了。
/*Accepted 2076K 360MS C++ 1203B 2012-08-06 12:58:49*/ #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> using namespace std; const int MAXN = 50050, inf = 0x3f3f3f3f; int u[MAXN * 3], v[MAXN * 3], w[MAXN * 3]; int a, b, c, e, dist[MAXN]; int n, right; void addedge(int a, int b, int c) { u[e] = a, v[e] = b, w[e] = c; e ++; } void ReadGraph() { int i; e = 0, right = 0; memset(dist, 0, sizeof dist); for(i = 0; i < n; i ++) { scanf("%d%d%d", &a, &b, &c); if(b > right) right = b; addedge(b, a - 1, -c); } for(i = 0; i < right; i ++) { addedge(i, i + 1, 1); addedge(i + 1, i, 0); } } int BellmanFord(int S, int T) { int i; bool flag; while(flag) { flag = false; for(i = 0; i < e; i ++) { if(dist[v[i]] > dist[u[i]] + w[i]) { flag = true; dist[v[i]] = dist[u[i]] + w[i]; } } } return dist[S] - dist[T]; } int main() { while(scanf("%d", &n) == 1) { ReadGraph(); printf("%d\n", BellmanFord(right, 0)); } return 0; }
下面是SPFA的代码:
/*Accepted 2776K 422MS C++ 1687B 2012-08-06 11:19:26*/ #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> using namespace std; const int MAXN = 50050, inf = 0x3f3f3f3f; int first[MAXN], next[MAXN * 3], v[MAXN * 3], w[MAXN * 3]; int a, b, c, e, dist[MAXN], inq[MAXN]; int n, right; void addedge(int a, int b, int c) { v[e] = b, w[e] = c; next[e] = first[a], first[a] = e ++; } void ReadGraph() { int i; e = 0, right = 0; memset(first, -1, sizeof first); for(i = 0; i < n; i ++) { scanf("%d%d%d", &a, &b, &c); ++ a, ++ b; if(b > right) right = b; addedge(b, a - 1, -c); } for(i = 1; i <= right; i ++) { dist[i] = inf; addedge(i - 1, i, 1); addedge(i, i - 1, 0); } } int SPFA(int S, int T) { queue<int> q; memset(inq, 0, sizeof (int) * (right + 1)); dist[0] = inf; dist[S] = 0; q.push(S); inq[S] = 1; while(!q.empty()) { int x = q.front(); q.pop(); inq[x] = 0; for(int i = first[x]; i != -1; i = next[i]) { if(dist[v[i]] > dist[x] + w[i]) { dist[v[i]] = dist[x] + w[i]; if(!inq[v[i]]) { inq[v[i]] = 1; q.push(v[i]); } } } } return dist[T]; } int main() { while(scanf("%d", &n) == 1) { ReadGraph(); printf("%d\n", -SPFA(right, 0)); } return 0; }