Description
Input
Output
Sample Input
5 3 7 3 8 10 3 6 8 1 1 3 1 10 11 1
Sample Output
6
题意:构造一个集合,这个集合内的数字满足所给的n个条件,每个条件都是指在[a,b]内至少有c个数在集合内。问这个集合最少包含多少个点。即求至少有多少个元素在区间[a,b]内。
分析:用ti表示在[0,i-1]的范围内,要选多少个数,对于题目中所说的每个条件[a,b]内至少有c个数在集合可以表示为t(b+1)-t(a)>=c,差分约束系统的雏形已经形成。但是,题目还有一个隐藏的条件,ti表示的是在[0,i-1]的范围内,要选多少个数,数列ti是递增的,但是增量最大是1,也就是说0<=t(i)-t(i-1)<=1,这个式子等价于t(i)-t(i-1)<=1和t(i-1)-t(i)<=0。用spfa算法得到一个最长路,第一个到最后一个节点的最长路即是需要求的值。
AC代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #define INF 1000000 5 using namespace std; 6 typedef struct 7 { 8 int v,w,next; 9 }Node; 10 Node e[250000]; 11 int first[50010],vis[50010],dist[50010]; 12 int n,g,minx,maxx; 13 void add(int u,int v,int w) 14 { 15 e[g].v=v; 16 e[g].w=w; 17 e[g].next=first[u]; 18 first[u]=g++; 19 } 20 void SPFA() 21 { 22 int i,j,t; 23 queue<int> q; 24 for(i=minx;i<=maxx;i++) 25 { 26 vis[i]=0; 27 dist[i]=-INF; 28 } 29 while(!q.empty()) 30 q.pop(); 31 dist[minx]=0; 32 vis[minx]=1; 33 q.push(minx); 34 while(!q.empty()) 35 { 36 t=q.front(); 37 q.pop(); 38 vis[t]=0; 39 for(i=first[t];i!=-1;i=e[i].next) 40 { 41 j=e[i].v; 42 if(dist[j]<dist[t]+e[i].w) 43 { 44 dist[j]=dist[t]+e[i].w; 45 if(!vis[j]) 46 { 47 vis[j]=1; 48 q.push(j); 49 } 50 } 51 } 52 } 53 } 54 int main() 55 { 56 int ai,bi,ci,i; 57 scanf("%d",&n); 58 memset(first,-1,sizeof(first)); 59 g=0; minx=INF; maxx=0; 60 for(i=1;i<=n;i++) 61 { 62 scanf("%d%d%d",&ai,&bi,&ci); 63 if(ai<minx) 64 minx=ai; 65 if(bi+1>maxx) 66 maxx=bi+1; 67 add(ai,bi+1,ci); 68 } 69 for(i=minx;i<=maxx;i++) 70 { 71 add(i,i-1,-1); 72 add(i-1,i,0); 73 } 74 SPFA(); 75 printf("%d\n",dist[maxx]); 76 return 0; 77 }