算法总结--广搜4{传送门}
feizhu_QWQ · · 算法·理论
| (。・∀・)ノ゙嗨,飞竹小课堂第 我们又是 今天我们学习传送门!! 第一道,免费传送门 免费传送门不仅要求传送门不花费步数,而且遇到了必须使用 如果我们把传送门和普通地方一样都标记了怎么办? 那么你有没有想过,传送门需要使用两次? |
# | # | # | # | # | # | # | # | # | # |
|---|---|---|---|---|---|---|---|---|---|---|
| # | @ | . | A | . | = | # | A | . | # | |
| # | # | # | # | # | # | # | # | # | # |
如果是这个地图,你必须先传送完后,在传送回来。
因为你唯一的路被堵住了,只能传送完后再传回来,才能走到终点。
所以免费传送门的套路就只有这一个,不要标记传送门!!!!
接着,你需要一个
代码展示:
#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[1005][1005];
bool vis[1005][1005];
struct node
{
int x,y;
}q[1000005];
int head=0,tail=1;
node pre[1005][1005];
bool check(int x,int y)
{
if(x<1||x>n||y<1||y>m||vis[x][y]==true) return false;
else return true;
}
void print(int x,int y)
{
if(x==-1&&y==-1) return;
print(pre[x][y].x,pre[x][y].y);
if(x==n&&y==m)
{
cout<<n<<" "<<m<<endl;
exit(0);
}
else cout<<x<<" "<<y<<endl;
}
bool work(int x,int y,int sx,int sy)
{
if(check(x,y)==true)
{
head++;
q[head].x=x;
q[head].y=y;
pre[x][y].x=sx;
pre[x][y].y=sy;
vis[x][y]=true;
if(x==n&&y==m) return true;
}
return false;
}
void bfs()
{
head++;
q[head].x=1;
q[head].y=1;
pre[1][1].x=-1;
pre[1][1].y=-1;
vis[1][1]=true;
while(head-tail+1>0)
{
int x=q[tail].x;
int y=q[tail].y;
tail++;
if(work(x-1,y,x,y)==true) print(x-1,y);
if(work(x+1,y,x,y)==true) print(x+1,y);
if(work(x,y-1,x,y)==true) print(x,y-1);
if(work(x,y+1,x,y)==true) print(x,y+1);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
if(a[i][j]=='*') vis[i][j]=true;
}
}
bfs();
return 0;
}
应该不是很难吧!
难的来了!
花费传送门问题
这道题和上一道有三点不同,第一是传送门不止两个互相传送。
第二是传送门需要花费!!
三是不一定必须传送!!
如果是在移动时枚举我们要传送到哪个传送门那里,将会增加很多空间复杂度!!!!
我们做个假设:
我们要从
所以我们推断出,我们最多使用一次传送门
所以我们可以推出来两种答案:
①不使用传送门
那就普通
②使用传送门
我们只会使用一次传送,就之用枚举两那个传送门了。
可在极限数据下,这样的优化还是会爆时间复杂度。
我们本来的答案应该是到达离起点最近的传送门要多久 + 离起点最近的传送门的消耗 + 离终点最近的传送门的消耗 + 离终点最近的传送门到终点要多久。
我们把前两者合并为一个,后两者合并为一个,简称
其实我们不用枚举,我们只用找到离起点最近的传送门和离终点最近的传送门就可以了。
我们跑两遍
第一遍以起点为起点,求每个传送门到起点需要走多远
第二遍以终点为起点,求每个传送门到终点需要走多远。
接着把每个传送门到起点/终点要多久加上自己的花费,就有了
我们把
应该不难吧。
代码较长,等飞竹写完再展示~
今天的传送门结束了!
ヾ( ̄▽ ̄)Bye~Bye~