bzoj 4070 [Apio2015]雅加达的摩天楼 Dijkstra+建图

[Apio2015]雅加达的摩天楼

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 644  Solved: 238
[Submit][Status][Discuss]

Description

 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1。除了这 N 座摩天楼外,雅加达市没有其他摩天楼。

 
有 M 只叫做 “doge” 的神秘生物在雅加达市居住,它们的编号依次是 0 到 M−1。编号为 i 的 doge 最初居住于编号为 Bi 的摩天楼。每只 doge 都有一种神秘的力量,使它们能够在摩天楼之间跳跃,编号为 i 的 doge 的跳跃能力为 Pi (Pi>0)。
 
在一次跳跃中,位于摩天楼 b 而跳跃能力为 p 的 doge 可以跳跃到编号为 b−p (如果 0≤b−p<N)或 b+p (如果 0≤b+p<N)的摩天楼。
 
编号为 0 的 doge 是所有 doge 的首领,它有一条紧急的消息要尽快传送给编 号为 1 的 doge。任何一个收到消息的 doge 有以下两个选择:
 
跳跃到其他摩天楼上;
将消息传递给它当前所在的摩天楼上的其他 doge。
请帮助 doge 们计算将消息从 0 号 doge 传递到 1 号 doge 所需要的最少总跳跃步数,或者告诉它们消息永远不可能传递到 1 号 doge。
 

Input

输入的第一行包含两个整数 N 和 M。

 
接下来 M 行,每行包含两个整数 Bi 和 Pi。
 

Output

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

 

Sample Input

5 3
0 2
1 1
4 1

Sample Output

5
explanation
下面是一种步数为 5 的解决方案:
0 号 doge 跳跃到 2 号摩天楼,再跳跃到 4 号摩天楼(2 步)。
0 号 doge 将消息传递给 2 号 doge。
2 号 doge 跳跃到 3 号摩天楼,接着跳跃到 2 号摩天楼,再跳跃到 1 号摩天楼(3 步)。
2 号 doge 将消息传递给 1 号 doge。

HINT

 

 子任务


所有数据都保证 0≤Bi<N。

 

子任务 1 (10 分)

1≤N≤10

1≤Pi≤10

2≤M≤3

子任务 2 (12 分)

1≤N≤100

1≤Pi≤100

2≤M≤2000

子任务 3 (14 分)

1≤N≤2000

1≤Pi≤2000

2≤M≤2000

子任务 4 (21 分)

1≤N≤2000

1≤Pi≤2000

2≤M≤30000

子任务 5 (43 分)

1≤N≤30000

1≤Pi≤30000

2≤M≤30000

 

题目看起来就像最短路,但是建图十分棘手,可以思考一下分块,当时想的时候并不怎么

会,设p为块的大小,对于大于p的话,最多只有n/p的边,直接暴力建边就可以了,对于剩

下的边,我们分层,分出p层,第i层,向其左右距离为i的点连边,每一层向最底层连边,这

样,当一个点的跳跃距离为x<=p时,最底层向x层连边,最后判断一下最底层然后就可以了,

具体的花费时间考虑一下没什么问题,然后当p取根号的时候比较优秀吧,Dijkstra就好了。

 

 1 #include<cstring>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 
 8 #define F(i,j,n) for(int i=j;i<=n;i++)  
 9 #define D(i,j,n) for(int i=j;i>=n;i--)  
10 #define ll long long  
11 #define maxn 30005*105  
12 #define maxm 30005*500  
13 #define inf 1000000000  
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
19     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
20     return x*f;
21 }
22 
23 int n,m,s,t,tot,tmp;  
24 int b[30005],p[30005],head[maxn],dis[maxn];  
25 bool inq[maxn];  
26 struct edge_type{int next,to,v;}e[maxm];  
27 queue<int> q;  
28 
29 inline void add_edge(int x,int y,int v)  
30 {  
31     e[++tot]=(edge_type){head[x],y,v};head[x]=tot;  
32 }  
33 inline void spfa()  
34 {  
35     memset(dis,-1,sizeof(dis));  
36     dis[s]=0;q.push(s);inq[s]=true;  
37     while (!q.empty())  
38     {  
39         int x=q.front();q.pop();inq[x]=false;  
40         for(int i=head[x];i;i=e[i].next)  
41         {  
42             int y=e[i].to;  
43             if (dis[y]==-1||dis[y]>dis[x]+e[i].v)  
44             {  
45                 dis[y]=dis[x]+e[i].v;  
46                 if (!inq[y]) q.push(y),inq[y]=true;  
47             }  
48         }  
49     }  
50 }  
51 inline int num(int x,int y)  
52 {  
53     return x*n+y;  
54 }  
55 int main()  
56 {  
57     n=read();m=read();  
58     F(i,1,m) b[i]=read()+1,p[i]=read();  
59     s=b[1];t=b[2];  
60     tmp=min((int)sqrt(n),100);  
61     F(i,1,tmp) F(j,1,n) add_edge(num(i,j),j,0);  
62     F(i,1,tmp) F(j,1,n-i) add_edge(num(i,j),num(i,j+i),1),add_edge(num(i,j+i),num(i,j),1);  
63     F(i,1,m)  
64     {  
65         if (p[i]<=tmp) add_edge(b[i],num(p[i],b[i]),0);  
66         else  
67         {  
68             for(int j=1;b[i]+j*p[i]<=n;j++) add_edge(b[i],b[i]+j*p[i],j);  
69             for(int j=1;b[i]-j*p[i]>=1;j++) add_edge(b[i],b[i]-j*p[i],j);  
70         }  
71     }  
72     spfa();  
73     printf("%d\n",dis[t]);  
74 }  

 

posted @ 2018-04-09 13:47  Kaiser-  阅读(217)  评论(0编辑  收藏  举报