题目链接:http://poj.org/problem?id=1201
题目说[ai, bi]区间内和点集Z至少有ci个共同元素,那也就是说如果我用Si表示区间[0,i]区间内至少有多少个元素的话,那么Sbi - Sai >= ci,这样我们就构造出来了一系列边,权值为ci,但是这远远不够,因为有很多点依然没有相连接起来(也就是从起点可能根本就还没有到终点的路线),此时,我们再看看Si的定义,也不难写出0<=Si - Si-1<=1的限制条件,虽然看上去是没有什么意义的条件,但是如果你也把它构造出一系列的边的话,这样从起点到终点的最短路也就顺理成章的出现了。
我们将上面的限制条件写为同意的形式:
Sbi - Sai >= ci
Si - Si-1 >= 0
Si-1 - Si >= -1
因为要求的是最小有多少个,所以要求最长路;
所以求出图中最小点到最大点的最大距离即可;
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <queue> #include <stack> #include <algorithm> #include <map> #include <string> typedef long long LL; #define INF 0x3f3f3f3f #define met(a, b) memset(a, b, sizeof(a)) #define N 51500 using namespace std; int S, E, vis[N], dist[N]; struct node { int u, v, w, Next; }e[N*3]; int Head[N], cnt; void Add(int u, int v, int w) { e[cnt].v = v; e[cnt].w = w; e[cnt].Next = Head[u]; Head[u] = cnt++; } int spfa() { for(int i=0; i<=E; i++) dist[i] = -INF; met(vis, 0); queue<int> Q; Q.push(S); vis[S] = 1; dist[S] = 0; while(!Q.empty()) { int p = Q.front();Q.pop(); vis[p] = 0; for(int i=Head[p]; i!=-1; i=e[i].Next) { int q = e[i].v; if(dist[q] < dist[p]+e[i].w)///最长路; { dist[q] = dist[p]+e[i].w; if(!vis[q]) { vis[q] = 1; Q.push(q); } } } } return dist[E]; } int main() { int n, u, v, w; while(scanf("%d", &n) != EOF) { met(e, 0); met(Head, -1); cnt = 0; S = INF; E = -INF;///找到对应的起点和终点; for(int i=1; i<=n; i++) { scanf("%d %d %d", &u, &v, &w); Add(u, v+1, w);///u可能等于0,所以v+1比较好; S = min(u, S); E = max(v+1, E); } for(int i=S; i<E; i++)///建立其他边,所以e要开3倍的N; { Add(i, i+1, 0); Add(i+1, i, -1); } int ans = spfa(); printf("%d ", ans); } return 0; }