呃,这是我做的第一道差分约束题,想先谈谈我对差分约束的理解,由于本人能力有限,可能理解有点浅显。如果您已看过相关讲解,请无视之。。。。
1、想看的是百度百科和维基百科上对差分约束的的定义,上面都举了同一个例子,就是,寻找一个5个向量x=(xi)以满足下列8个差分约束条件:
x1-x2≤0 ,x1-x5≤-1 ,x2-x5≤1 ,x3-x1≤5 ,x4-x1≤4 ,x4-x3≤-1 ,x5-x3≤-3 ,x5-x4≤-3
然后讲了用Bellman_ford求最短路的方法来实现差分约束。
2、然后,看了这道题,本以为会是一道裸的差分约束题,想了一会,很是没思路,很没“骨气”的查了解题报告,结果又了解了一点知识,那就是通过最短路径算法求出来的一组解当中,所有未知数都达到最大值,由此有查到了一篇讲差分约束很好的Blog,http://imlazy.ycool.com/post.1702305.html里面讲的很详细,而且也简单的证明了上面那句话,虽然没想出具体方法验证,但是他的讲解还是让我明白了这个结论。个人觉得这篇Blog让我受益最大。
还有下面这个对这题的讲解最详细
http://blog.csdn.net/morgan_xww/article/details/6359229
但是http://blog.csdn.net/guzhilei1986/article/details/2305137做法更简单。
下面说说这题吧。
题意:给出N个区间以及每个区间对应的整数,计算一个有最小元素个数的集合,使得对于每个给出的区间,集合与它的相同元素个数不小于相应的整数。
思路:呃, 首先要承认,这题的思路真不是自己的思路,参考了解题报告。假设,dis[i+1] 代表源点到xi 点的满足题目中要求的最少的点数,因此可以得出不等式dis[j] - dis[i-1] >= ci;
即dis[j] >= dis[i-1] + ci,有这个不等式我们很容易想到单源最短路,但是上面说咯额,通过最短路方法求出的一组解中,所有未知数都达到最大值,题目中要求的是从s点到t点的最少数目的点,所以我们要改为求最长路,为什么要这样,可以参考第一Blog中的讲解。但是只有上面的不等式是不够得,题目中还有一个隐藏的要求, 即0<= dis[j+1] - dis[j] <= 1 ,由此可以求出满足要求的最少的点。
代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> #define N 50005 #define M 100000 #define INF 0xffff using namespace std ; struct node { int s ; int e ; int val ; }p[N] ; int dis[M] ; int minn , maxx ; int Bellman_ford ( int n ) { int i , j , flag ; for ( i = minn ; i <= maxx ; i++ ) dis[i] = -INF; dis[minn] = 0 ; for ( i = 0 ; i <= maxx - minn ; i++ ) { flag = 0 ; for ( j = 1 ; j <= n ; j++ ) { if ( dis[p[j].s] != -INF && dis[p[j].s] + p[j].val > dis[p[j].e] ) { dis[p[j].e] = dis[p[j].s] + p[j].val ; flag = 1 ; } } for ( j = minn ; j < maxx ; j++ ) { if ( dis[j] != -INF && dis[j] > dis[j+1] ) { dis[j+1] = dis[j] ; flag = 1 ; } } for ( j = maxx ; j > minn ; j-- ) { if ( dis[j] != -INF && dis[j] - 1 > dis[j-1] ) { dis[j-1] = dis[j] - 1; flag = 1 ; } } if ( !flag ) break; } return dis[maxx] ; } int main() { int n , i ; while ( scanf ( "%d" , &n ) != EOF ) { minn = INF ; maxx = -INF ; for ( i = 1 ; i <= n ; i++ ) { scanf ( "%d%d%d" , &p[i].s , &p[i].e , &p[i].val ); p[i].e++ ; if ( p[i].s < minn ) minn = p[i].s ; if ( p[i].e > maxx ) maxx = p[i].e ; } printf ( "%d\n" , Bellman_ford( n )); } return 0 ; }