想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
转载请注明出处:http://blog.csdn.net/wangjian8006
题目大意:有n个区间,每个区间有3个值,ai,bi,ci代表,在区间[ai,bi]上至少要选择ci个整数点,ci可以在区间内任意取不重复的点
现在要满足所有区间的自身条件,问最少选多少个点
解题思路:
差分约束的思想:可以肯定的是s[bi]-s[ai-1]>=ci; 为什么要ai-1,是因为ai也要选进来
在一个是s[i]-s[i-1]<=1;
s[i]-s[i-1]>=0
所以整理上面三个式子可以得到约束条件:
①s[ai-1]-s[bi] <= -ci
②s[i]-s[i-1] <= 1
③s[i-1]-s[i] <= 0
而我们要所求的是从区间的最小点到区间最大点的所取的点的总个数最小。所以从源点(所有区间的最小点)到终点(所有区间的最大点)求最短路
这里要注意边界问题,就是最小点也要取进来,否则会出错
这里我们在添加边的时候,i->i-1和i-1->i这些边不要加进来,因为可以直接判断,所以总的边数最多就是50000条边
那么②和③在求最短路的时候直接从头到尾判断一次
/* Memory 948K Time 219MS */ #include <iostream> using namespace std; #define MAXV 50002 #define INF INT_MAX #define min(a,b) (a>b?b:a) #define max(a,b) (a<b?b:a) typedef struct{ int s,t,w; }Edge; Edge edge[MAXV]; int n,d[MAXV],mi,ma; void bellman_ford(){ int i; bool flag=true; while(flag){ flag=false; for(i=1;i<=n;i++){ //要使所有的点满足s[ai-1]-s[bi] <= -ci if(d[edge[i].t]>d[edge[i].s]-edge[i].w){ d[edge[i].t]=d[edge[i].s]-edge[i].w; flag=true; } } for(i=mi;i<=ma;i++){ //要使所有点满足s[i]-s[i-1] <= 1 if(d[i]>d[i-1]+1){ d[i]=d[i-1]+1; flag=true; } } for(i=ma;i>=mi;i--){ //要使所有点满足s[i-1]-s[i] <= 0 if(d[i-1]>d[i]){ d[i-1]=d[i]; flag=true; } } } } int main(){ int i; while(~scanf("%d",&n)){ mi=INF,ma=-1; for(i=1;i<=n;i++){ scanf("%d%d%d",&edge[i].t,&edge[i].s,&edge[i].w); mi=min(mi,edge[i].t); //找出源点与终点 ma=max(ma,edge[i].s); d[i]=0; //初始化 edge[i].t--; //使得ai-1 } bellman_ford(); printf("%d\n",d[ma]-d[mi-1]); //这里要包括最小点,所以是mi-1,否则会出错 } return 0; }