差分约束的思想,虽然很长时间没写了。。。
用d[i]表示区间[0..i]选的个数,那么对于给出的每个区间有d[b[i]] - d[a[i] - 1] >= c[i],此外还有隐藏约束条件0<=d[i] - d[i - 1]<=1。
考虑图论中的最长路的性质,连边a[i - 1]——>b[i],权为c[i]。对每个节点i连边i——>i+1,权为0;i+1——>i,权为-1,应用spfa跑最长路。
在得出最长路的图中,一定满足上述两个约束条件,那么此时d[n]就代表了满足上述所有约束条件的最小选取个数。


#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<map> #include<cstdlib> #include<cmath> using namespace std; #define ll long long #define pb push_back int d[55555]; bool v[55555]; int g[55555]; int nume; struct edge { int w,v,nxt; }; edge e[555555]; int n,m; int spfa() { queue<int>q; while (!q.empty()) q.pop(); q.push(0); memset(d,-1,sizeof(d)); memset(v,0,sizeof(v)); d[0] = 0; v[0] = 1; while (!q.empty()) { int x = q.front(); q.pop(); for (int i = g[x]; i; i=e[i].nxt) { //cout<<x<<" "<<e[i].v<<" "<<endl; if (d[e[i].v] < d[x] + e[i].w) { //cout<<x<<" "<<e[i].v<<endl; d[e[i].v] = d[x] + e[i].w; if (!v[e[i].v]) { q.push(e[i].v); v[e[i].v] = 1; } } } v[x] = 0; } return d[m + 1]; } void init() { nume = 1; memset(g,0,sizeof(g)); } void addedge(int u,int v,int c) { ++nume; e[nume].v = v; e[nume].w = c; e[nume].nxt = g[u]; g[u] = nume; } int main() { while (scanf("%d",&n) != EOF) { m = 0; init(); //for (int i = 1; i <= n; i++) scanf("%d%d%d",&t[i].a,&t[i].b,&t[i].c); int x,y,z; for (int i = 1; i <= n; i++) { scanf("%d%d%d",&x,&y,&z); y++; m = max(m,y); addedge(x,y,z); } for (int i = 0; i <= m; i++) { addedge(i,i + 1,0); addedge(i + 1,i,-1); } printf("%d\n",spfa()); //for (int i = 0; i <= m + 1; i ++) cout<<i<<" "<<d[i]<<endl; } return 0; }