BZOJ3387栅栏(另一种解法:spfa)

题目描述 + 讲解

经典例题了,常规解法是 用线段树优化dp数组,dp很好想,线段树优化难写。
这里我给出另一种解法,最短路spfa。(也不好想)


因为只要求x轴上的运动路径。所以只有栅栏的边界是有用的。想象他的总体运动轨迹时,可以以边界为点,相互连线(斜的不影响),之间距离为x轴距离差。

最短路解法的关键是尽量建少的边。

从上面运动到下面,和从下面移动下面是一样的。
因为他输入的数据是从下到上。所以从下至上考虑也可以。

对于之前的端点(不管左右),如果在现在的[x,y]内,可能存在阻拦,然后用左右端点与之建边,并去除改节点。然后储存进现在这两个端点。

set不重复,且自动排序。首先他不影响建边,遇到相同时,建的边长度为0。因为他的不重复,可以少建边。


部分代码:

int n,s,head[maxn],cnt,d[maxn],c;
bool vis[maxn];
set<int>sz;
map<int,int>mp;
struct edge{	int to,w,next;	}e[maxn];
void add(int u,int v,int w){
	e[++cnt].w=w;	e[cnt].to=v;
	e[cnt].next=head[u];	head[u]=cnt;
}
void spfa(){
	queue<int>q;	q.push(1);	
	memset(d,inf,sizeof(d));	d[1]=0;	vis[1]=1; 
	while(!q.empty()){
		int x=q.front();	vis[x]=0;	q.pop();
		for(int i=head[x];i;i=e[i].next){
			int y=e[i].to,w=e[i].w;
			if(d[y]>d[x]+w){
				d[y]=d[x]+w;
				if(!vis[y]){	q.push(y);	vis[y]=1;	}
			}
		}
	}
}
int main(){
	n=read();	s=read();
	sz.insert(0);	mp[0]=1;	c++;
	set<int>::iterator it;
	for(int i=0;i<n;i++){
		int x,y;	x=read();	y=read();
		it=sz.lower_bound(x);
		while(it!=sz.end()){
			int t=(*it);
			if(t>y)	break;
			add(mp[t],c+1,t-x);
			add(mp[t],c+2,y-t);
			it++;
			sz.erase(t);
		}
		mp[x]=++c;	mp[y]=++c;
		sz.insert(x);	sz.insert(y);
	}
	c++;
	for(it=sz.begin();it!=sz.end();it++)	add(mp[(*it)],c,abs(s-(*it)));
	spfa();
	printf("%d",d[c]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值