Description
有一副n*m的地图,有n*m块地,每块是下列四种中的一种:
墙:用#表示,墙有4个面,分别是前面,后面,左面,右面。
起点:用C表示,为主角的起点,是一片空地。
终点:用F表示,为主角的目的地,是一片空地。
空地:用 . 表示。
其中除了墙不能穿过,其他地方都能走。
主角有以下3种操作:
1.移动到相邻的前后左右的地方,花费一个单位时间。
2.向前后左右其中一个方向发射子弹,子弹沿直线穿过,打在最近的一堵墙的一面,然后墙的这面就会形成一个开口通往秘密通道。同一时间最多只能有两个开口,若出现有3个开口,出现时间最早的开口会立即消失。该操作不用时间。
3.可以从一个与开口相邻的空地跳进去,进入秘密通道,从另外一个开口正对的空地跳出来。这个过程花费一个单位时间。
地图四周都是墙,问主角最少用多少时间从C走到F。C和F
只会出现一次。
先说说我之前的解法吧,估计有问题
因为打枪不消耗时间,所以随便走就可以了。
然后我打了搜索
其实完全可以再进一步
向四周连边,再向墙连边,边权为最近的墙的距离。
跑一遍Dijkstra就行,但是注意不能反向边
因为从To到From的情况和From到To是不一样的,To和From所处的位置本就不同
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 505;
char Map[MAXN][MAXN];
int Stx,Sty,Edx,Edy;
int Dis[MAXN * MAXN];
int n,m;
struct _Edge{
int Next;
int To;
int Wei;
} Edge[MAXN * MAXN * 10];
int Head[MAXN * MAXN],Cnt;
void Add(int u,int v,int w) {
Cnt ++;
Edge[Cnt].Next = Head[u];
Edge[Cnt].To = v;
Edge[Cnt].Wei = w;
Head[u] = Cnt;
}
struct _Wall{
int x,y;
} Wall[10];
struct Unit{
int x;
int w;
bool operator < (const Unit & a) const {
return w > a.w;
}
};
int Loss[7][7] = {{1,0},{-1,0},{0,1},{0,-1}};
int Vis[MAXN * MAXN];
void Dijkstra() {
priority_queue<Unit> que;
memset(Dis,0x3f,sizeof(Dis));
Dis[(Stx - 1) * n + Sty] = 0;
que.push((Unit) {
(Stx - 1) * n + Sty,0
});
while(!que.empty()) {
int x = que.top().x;
que.pop();
if(Vis[x]) continue;
Vis[x] = 1;
for(int i = Head[x]; i; i = Edge[i].Next) {
int y = Edge[i].To;
if(Dis[x] + Edge[i].Wei < Dis[y]) {
Dis[y] = Dis[x] + Edge[i].Wei;
if(!Vis[y]) que.push((Unit) {
y,Dis[y]
});
}
}
}
}
int main() {
freopen("portal.in","r",stdin);
freopen("portal.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) {
scanf("%s",Map[i] + 1);
for(int j = 1; j <= m; j++) {
if(Map[i][j] == 'C') {
Stx = i;
Sty = j;
}
if(Map[i][j] == 'F') {
Edx = i;
Edy = j;
}
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
int From = (i - 1) * n + j;
if(Map[i][j] != '#') {
int x = i,y = j;
int tx = x,ty = y,d = 10000;
while(Map[tx][ty] != '#') tx --;
Wall[1].x = tx;
Wall[1].y = ty;
d = min(d,x - tx);
tx = x,ty = y;
while(Map[tx][ty] != '#') tx ++;
Wall[2].x = tx;
Wall[2].y = ty;
d = min(d,tx - x);
tx = x,ty = y;
while(Map[tx][ty] != '#') ty --;
Wall[3].x = tx;
Wall[3].y = ty;
d = min(d,y - ty);
tx = x,ty = y;
while(Map[tx][ty] != '#') ty ++;
Wall[4].x = tx;
Wall[4].y = ty;
d = min(d,ty - y);
for(int k = 1; k <= 4; k++) {
int To = (Wall[k].x - 1 + Loss[k - 1][0]) * n + Wall[k].y + Loss[k - 1][1];
Add(From,To,d);
}
for(int k = 0; k < 4; k++) {
int tx = i + Loss[k][0],ty = j + Loss[k][1];
if(tx < 1 || tx > n || ty < 1 || ty > m || Map[tx][ty] == '#') continue;
int To = (tx - 1) * n + ty;
Add(From,To,1);
}
}
}
}
Dijkstra();
if(Dis[(Edx - 1) * n + Edy] != 0x3f3f3f3f)
cout << Dis[(Edx - 1) * n + Edy];
else cout << "nemoguce";
return 0;
}