poj 1201 差分约束
转自:優YoU http://user.qzone.qq.com/289065406/blog/1307063918
大致题意:
给出数轴上的n个区间[ai,bi],每个区间都是连续的int区间。
现在要在数轴上任意取一堆元素,构成一个元素集合V
要求每个区间[ai,bi]和元素集合V的交集至少有ci不同的元素
求集合V最小的元素个数。
解题思路:
设s[x] = 从0 到x 的所有在集合中的数的个数
则ai到bi的个数即S[bi] - S[ai-1]。
因此有
(1) S[bi] - S[ai-1] >= ci。
又根据s[x]本身的性质,后面的一定不比前面的小,后面的最多比前面多一,有:
(2) s[i + 1] - s[i] >= 0
(3) s[i + 1] - s[i] <= 1
故建图,使图中每一组边,均满足(注意三条式子的不等号方向要一致,这个很重要):
S[ai - 1] <= S[bi] - ci
S[i] <= S[i - 1] + 1
S[i - 1] <= S[i]
上面三式,可把s[x]看作源点(假设存在)到各点的最短距离,初始化为0;
常数为边(ai – 1,bi)的边权
当存在不满足这三条式子的边时,对这条边进行Relax操作,更新不等号左边的变量。
其实就是Bellman-Ford算法的核心部分
if( S[ai - 1] > S[bi] – 2 ) S[ai - 1] = S[bi] – ci ;
if( S[i] > S[i - 1] + 1 ) S[i] > S[i - 1] + 1 ;
if( S[i - 1] > S[i] ) S[i - 1] = S[i] ;
最后源点到最大顶点的距离减去源点到最小顶点的距离就是所求(其实一个单位距离就代表V中的一个元素;最小顶点到最大顶点其实就是所有输入的区间中,最小的左端点到最大的右端点这个范围)
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <algorithm> 5 #include <iostream> 6 #include <map> 7 #include <queue> 8 #include <stack> 9 #include <cmath> 10 //#pragma comment(linker, "/STACK:102400000,102400000") 11 using namespace std; 12 #define PF(x) cout << "debug: " << x << " "; 13 #define EL cout << endl; 14 #define PC(x) puts(x); 15 typedef long long ll; 16 #define CLR(x, v) sizeof (x, v, sizeof(x)) 17 using namespace std; 18 const int INF = 0x5f5f5f5f; 19 const int N= 2e5 + 10; 20 const int mod=1e9 + 7; 21 const int maxn = 5e4 + 10; 22 int n,c[maxn],dis[maxn]; 23 struct st{ 24 int s,e; 25 }val[maxn]; 26 int main() 27 { 28 // freopen("in.txt","r",stdin); 29 while(~scanf("%d",&n)){ 30 int sta = INF,to = 0; 31 for(int i = 1;i <= n;i++){ 32 scanf("%d%d%d",&val[i].s,&val[i].e,&c[i]); 33 val[i].e++; 34 to = max(to,val[i].e); 35 sta = min(sta,val[i].s); 36 } 37 for(int i = 0;i <= n;i++) dis[i] = 0; 38 bool fg = false; 39 while(!fg){//注意不等式的变换,全部是变小 40 fg = true; 41 // cout<<1<<endl; 42 for(int i = 1;i <= n;i++) 43 if(dis[val[i].s] > dis[val[i].e] - c[i]){ 44 fg = false; 45 dis[val[i].s] = dis[val[i].e] - c[i]; 46 } 47 for(int i = sta;i < to;i++) 48 if(dis[i + 1] > dis[i] + 1){ 49 fg = false; 50 dis[i + 1] = dis[i] + 1; 51 } 52 for(int i = to - 1;i >= sta;i--) 53 if(dis[i] > dis[i + 1]){ 54 fg = false; 55 dis[i] = dis[i + 1]; 56 } 57 58 //cout<<dis[to] - dis[sta]<<endl; 59 60 } 61 cout<<dis[to] - dis[sta]<<endl; 62 } 63 return 0; 64 }