20200508 SCOI模拟T2(分层图最短路)

T2 [APIO2015]雅加达的摩天楼

P3645 [APIO2015]雅加达的摩天楼
题目描述
印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0N−1。除了这 N 座摩天楼外,雅加达市没有其他摩天楼。
M 只叫做 “doge” 的神秘生物在雅加达市居住,它们的编号依次是 0M−1。编号为 i 的 doge 最初居住于编号为 B i B_i Bi 的摩天楼。每只 doge 都有一种神秘的力量,使它们能够在摩天楼之间跳跃,编号为 i 的 doge 的跳跃能力为 P i ( P i > 0 ) P_i (P_i > 0) PiPi>0
在一次跳跃中,位于摩天楼 b 而跳跃能力为 p 的 doge 可以跳跃到编号为 b−p (如果 0 ≤ b − p < N 0 \leq b − p < N 0bp<N)或 b+p (如果 0 ≤ b + p < N 0 \leq b + p < N 0b+p<N)的摩天楼。
编号为 0 的 doge 是所有 doge 的首领,它有一条紧急的消息要尽快传送给编号为 1 的 doge。任何一个收到消息的 doge 有以下两个选择:
跳跃到其他摩天楼上;
将消息传递给它当前所在的摩天楼上的其他 doge。
请帮助 doge 们计算将消息从 0 号 doge 传递到 1 号 doge 所需要的最少总跳跃步数,或者告诉它们消息永远不可能传递到 1 号 doge。

输入格式
输入的第一行包含两个整数 NM
接下来 M 行,每行包含两个整数 B i B_i Bi P i P_i Pi

输出格式
输出一行,表示所需要的最少步数。如果消息永远无法传递到 1 号 doge,输出 −1

输入输出样例
输入
5 3
0 2
1 1
4 1
输出
5

说明/提示
【样例解释】
下面是一种步数为 5 的解决方案:
0 号 doge 跳跃到 2 号摩天楼,再跳跃到 4 号摩天楼(2 步)。
0 号 doge 将消息传递给 2 号 doge。
2 号 doge 跳跃到 3 号摩天楼,接着跳跃到 2 号摩天楼,再跳跃到 1 号摩天楼(3 步)。
2 号 doge 将消息传递给 1 号 doge。

【数据范围】
所有数据都保证 0 ≤ B i < N , 1 ≤ N ≤ 30000 , 1 ≤ P i ≤ 30000 , 2 ≤ M ≤ 30000 0 \leq B_i < N,1 \leq N \leq 30000,1 \leq P_i \leq 30000,2 \leq M \leq 30000 0Bi<N,1N30000,1Pi30000,2M30000

思路:
考虑一种建图方法,对于每一个 doge,向他可以到的所有点连边,边权为他到这个点的步数,在图上跑最短路即可
发现这样建图时间要炸,考虑优化,建立分层图
跳跃能力小于 n \sqrt n n 的 doge,对于每一种跳跃能力建立 n 个点,相邻的能到达的点之间连一条边权为 1 的边,对于每一个点,向原图对应点连一条边权为 0的边,对于每一个 doge,向他的跳跃能力的一层的对应点连一条边权为 0 的边。
跳跃能力大于 n \sqrt n n 的 doge,暴力建图
复杂度证明:对于第一种边,边数小于 n n n\sqrt n nn ,对于第二种边,边数小于 n n n\sqrt n nn
嫖张图理解一下

代码:

#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define re register

inline char ch(){
	static char buf[1<<21],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}

inline int in{
	int s=0,f=1;char x;
	for(x=ch();x<'0'||x>'9';x=ch())	if(x=='-')	f=-1;
	for( ;x>='0'&&x<='9';x=ch())	s=(s*10)+(x&15);
	return f==1?s:-s;	
}

const int A=1e7+5;
const int INF=1e9;
int n,m,blo,all;
inline int d(int x,int dep){
	return dep*n+x;
}
int head[A],tot_road=0;
struct Road{
	int nex,to,w;
}road[2*A];
inline void ljb(int x,int y,int w){
	road[++tot_road]={head[x],y,w};head[x]=tot_road;
}
int root,last;

inline void prepare(){
	for(re int i=1;i<=blo;++i)
		for(re int j=0;j<n;++j){
			if(i+j<n)	ljb(d(j,i),d(j+i,i),1),ljb(d(j+i,i),d(j,i),1);
			ljb(d(j,i),j,0);
		}
	return;
}

inline void build(int x,int val){
	int now=x,num=1;
	now+=val;
	while(now<n){
		ljb(x,now,num);
		now+=val,num++;
	}
	now=x,num=1;
	now-=val;
	while(now>=0){
		ljb(x,now,num);
		now-=val,num++;
	}
	return;
}

int dis[A];
bool ex[A];
priority_queue <pair<int,int> > q;

inline void djk(){
	fill(dis,dis+(blo+1)*n+1,INF);
	dis[root]=0;
	q.push(make_pair(0,root));
	while(!q.empty()){
		int x=q.top().second;q.pop();
		if(ex[x])	continue;
		ex[x]=1;
		for(re int y=head[x];y;y=road[y].nex){
			int z=road[y].to,w=road[y].w;
			if(dis[x]+w<dis[z]){
				dis[z]=dis[x]+w;
				q.push(make_pair(-dis[z],z));
			}
		}
	}
	return;
}

signed main(){
//	freopen("skyscraper.in","r",stdin);
//	freopen("skyscraper.out","w",stdout);
	n=in,m=in;
	blo=sqrt(n);
	prepare();
	for(re int i=0;i<m;++i){
		int u=in,v=in;
		if(v<=blo)	ljb(u,d(u,v),0);
		else	build(u,v);
		if(i==0)	root=u;
		if(i==1)	last=u;
	}
	djk();
	if(dis[last]==INF)	printf("-1\n");
	else	printf("%d\n",dis[last]);
	return 0;
}
中描述了一个幼儿园里分配糖果的问题,每个小朋友都有自己的要求。问题的输入包括两个整数NN和KK,表示幼儿园里的小朋友数量和要满足的要求数量。接下来的KK行表示小朋友们的要求,每行有三个数字,XX,AA,BB。如果X=1,表示第AA个小朋友分到的糖果必须和第BB个小朋友分到的糖果一样多;如果X=2,表示第AA个小朋友分到的糖果必须少于第BB个小朋友分到的糖果;如果X=3,表示第AA个小朋友分到的糖果必须不少于第BB个小朋友分到的糖果;如果X=4,表示第AA个小朋友分到的糖果必须多于第BB个小朋友分到的糖果;如果X=5,表示第AA个小朋友分到的糖果必须不多于第BB个小朋友分到的糖果。这个问题可以被看作是一个差分约束系统的问题。 具体地说,可以使用差分约束系统来解决这个问题。差分约束系统是一种通过给变量之间的关系添加约束来求解最优解的方法。对于这个问题,我们需要根据小朋友们的要求建立约束条件,并通过解决这个约束系统来得出最小的糖果数量。 在问题的输入中,X的取值范围为1到5,分别对应不同的关系约束。根据这些约束,我们可以构建一个差分约束图。图中的节点表示小朋友,边表示糖果数量的关系。根据不同的X值,我们可以添加相应的边和权重。然后,我们可以使用SPFA算法(Shortest Path Faster Algorithm)来求解这个差分约束系统,找到满足所有约束的最小糖果数量。 需要注意的是,在读取输入时需要判断X和Y是否合法,即是否满足X≠Y。如果X=Y,则直接输出-1,因为这种情况下无法满足约束条件。 综上所述,为了满足每个小朋友的要求,并且满足所有的约束条件,我们可以使用差分约束系统和SPFA算法来求解这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【差分约束系统】【SCOI2011】糖果 candy](https://blog.csdn.net/jiangzh7/article/details/8872699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [P3275 [SCOI2011]糖果(差分约束板子)](https://blog.csdn.net/qq_40619297/article/details/88678605)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值