您的位置:首页 > 其它

UVALive 5966 Blade and Sword -- 搜索(中等题)

2014-07-23 10:34 309 查看
题意:给一幅地图,P为起点,D为终点,'*'为传送阵,到达传送阵可以传到任意一个其他的传送阵,传到以后可以正常走或者再传回来,问P->D最短步数。

分析:这题一定要细心,分析要到位才能搞定,错一点都WA。有两种思路:

1.走到一个传送点之后,将所有能传到的地方都加入队列,然后清除传送阵向量(vector),因为以后不用再互相传了,对于某个传送阵k,以后从别的点传到k的效果还不如从这个点传到k,所以清空传送阵,又因为其他传送阵可以传回来,此时传送阵向量要把当前传送阵push_back进去,以便其他点传过来,每个传送点设一个标记,flag=0说明这个传送点还没用过,flag=1说明这个传送点是被传过来的,还可以传一次,use[][]数组记录某个传送点被用过没有(即通过它传出去过没有),然后搞即可。

代码:(63ms, 0KB)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define Mod 1000000007
using namespace std;
#define N 1000017

struct node
{
int x,y,step;
}P,D;

int n,m;
int cnt1,cnt2;
char ss[205][205];
int vis[205][205];
queue<node> que;
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
int X1,X2,Y1,Y2;

int OK(int nx,int ny)
{
if(nx >= 0 && nx < n && ny >= 0 && ny < m && ss[nx][ny] == '.')
return 1;
return 0;
}

int bfsPD()
{
while(!que.empty())
que.pop();
P.step = 0;
memset(vis,0,sizeof(vis));
que.push(P);
vis[P.x][P.y] = 1;
while(!que.empty())
{
node now = que.front();
que.pop();
int nx = now.x;
int ny = now.y;
int step = now.step;
for(int k=0;k<4;k++)
{
int kx = nx + dx[k];
int ky = ny + dy[k];
if(ss[kx][ky] == 'D')
return step+1;
if(!OK(kx,ky) || vis[kx][ky])  //不考虑'*'
continue;
node tmp;
tmp.x = kx;
tmp.y = ky;
tmp.step = step + 1;
vis[kx][ky] = 1;
que.push(tmp);
}
}
return Mod;
}

int bfsP()    //从P找'*'
{
int dis = Mod;
while(!que.empty())
que.pop();
memset(vis,0,sizeof(vis));
P.step = 0;
que.push(P);
vis[P.x][P.y] = 1;
while(!que.empty())
{
node now = que.front();
que.pop();
int nx = now.x;
int ny = now.y;
int step = now.step;
if(step >= dis)
return dis;
for(int k=0;k<4;k++)
{
int kx = nx + dx[k];
int ky = ny + dy[k];
if(ss[kx][ky] == '*')
{
X1 = kx;
Y1 = ky;
cnt1++;
dis = step + 1;
}
else if(OK(kx,ky))
{
if(!vis[kx][ky])
{
node tmp;
tmp.x = kx;
tmp.y = ky;
tmp.step = step+1;
vis[kx][ky] = 1;
que.push(tmp);
}
}
}
}
return dis;
}

int bfsD()    //从D找'*'
{
int dis = Mod;
while(!que.empty())
que.pop();
memset(vis,0,sizeof(vis));
D.step = 0;
que.push(D);
vis[D.x][D.y] = 1;
while(!que.empty())
{
node now = que.front();
que.pop();
int nx = now.x;
int ny = now.y;
int step = now.step;
if(step >= dis)
return dis;
for(int k=0;k<4;k++)
{
int kx = nx + dx[k];
int ky = ny + dy[k];
if(ss[kx][ky] == '*')
{
X2 = kx;
Y2 = ky;
cnt2++;
dis = step + 1;
}
else if(OK(kx,ky))
{
if(!vis[kx][ky])
{
node tmp;
tmp.x = kx;
tmp.y = ky;
tmp.step = step+1;
vis[kx][ky] = 1;
que.push(tmp);
}
}
}
}
return dis;
}

int main()
{
int t,cs = 1,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int cnt = 0;
for(i=0;i<n;i++)
{
scanf("%s",ss[i]);
for(j=0;j<m;j++)
{
if(ss[i][j] == 'P')
P.x = i,P.y = j;
else if(ss[i][j] == 'D')
D.x = i,D.y = j;
else if(ss[i][j] == '*')
cnt++;
}
}
int ans = 0;
cnt1 = cnt2 = 0;
if(cnt <= 1)    //少于等于1个传送点,就只能按普通路走过去
ans = bfsPD();
else
{
int d1,d2;
ans = bfsPD();
d1 = bfsP();
d2 = bfsD();
if(cnt1 == cnt2 && cnt1 == 1)  //周围都只有一个点,通过这两个点中介
{
if(X1 == X2 && Y1 == Y2)  //是同一个点,因为至少还有一个点,所以可以传回来
ans = min(ans,d1+d2+2);
else
ans = min(ans,d1+d2+1);
}
else  //有不止一个点,可以用不同点传
ans = min(ans,d1+d2+1);
}
if(ans >= Mod)
printf("Case %d: impossible\n",cs++);
else
printf("Case %d: %d\n",cs++,ans);
}
return 0;
}


View Code

Written by Whatbeg
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: