pku1201 差分约束系统

Intervals

这题依然 SPFA + 栈 过!

不同的是,这题有隐含条件,而且所求也大不一样。

由于这是对区间操作,求至少包含区间[ai, bi]中ci个点的最小集合。可以用集合元素个数来定义变量,即num[bi] - num[ai] >= ci, 但有个隐含条件就是,每个元素都是整点,取得话,最多为一,最少为0, 即 num[i+1] - num[i] <= 1, num[i+1] - num[i] >= 0, 将这些条件再转换成最短路里的边和权,就可以做了。

这里求得是至少,也就是最小值,即 num[maxn] - num[0] >= ans, 我们要转化成 <= 号,也就是 num[0] - num[maxn] <= -ans, 这样就行了,赋初值时,令dis[maxn] = 0,求得就是每个点到maxn的距离了,输出结果就是dis[0]加个负号。

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#include < stdio.h >
#include
< stdlib.h >
#define INF 0xfffffff
#define NN 50004
#define MM 150004
int edNum, maxn;
int mark[NN];
int root[NN];
int dis[NN];
int next[MM];
int stack[NN];
struct node{
int e, v;
}edge[MM];

void Init(){
int i;
for (i = 0 ; i < NN; i ++ ){
mark[i]
= 0 ;
root[i]
= - 1 ;
dis[i]
= INF;
}
}

void add( int a, int b, int c){
edge[edNum].e
= b;
edge[edNum].v
= c;
next[edNum]
= root[a];
root[a]
= edNum ++ ;
}

void Spfa()
{
int i, cur, nxt, tmp, top = 0 ;
for (i = 0 ; i <= maxn; i ++ ){
if (root[i] != - 1 ){
stack[
++ top] = i;
mark[i]
= 1 ;
}
}
// 这里需要注意,要将终点置零,求的就是别的点到终点maxn的距离
dis[maxn] = 0 ;
while (top){
cur
= stack[top -- ];
mark[cur]
= 0 ;
tmp
= root[cur];
while (tmp != - 1 ){
nxt
= edge[tmp].e;
if (dis[nxt] > dis[cur] + edge[tmp].v){
dis[nxt]
= dis[cur] + edge[tmp].v;
if ( ! mark[nxt]){
mark[nxt]
= 1 ;
stack[
++ top] = nxt;
}
}
tmp
= next[tmp];
}
}
}
int main()
{
int n, i, a, b, c;
scanf(
" %d " , & n);
maxn
= 0 ;
edNum
= 0 ;
Init();
for (i = 1 ; i <= n; i ++ ){
scanf(
" %d%d%d " , & a, & b, & c);
add(b
+ 1 , a, - c);
if (b + 1 > maxn){
maxn
= b + 1 ;
}
}
for (i = 0 ; i <= maxn; i ++ ){
add(i
+ 1 , i, 0 );
add(i, i
+ 1 , 1 );
}
Spfa();
// 输出的时候也要注意,是起点到终点的距离的负值
printf( " %d\n " , - dis[ 0 ]);
// system("pause");
return 0 ;
}

 

转载于:https://www.cnblogs.com/ylfdrib/archive/2010/07/23/1783665.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值