由于一些原因,本题无法把题目描述放上来,可以去OpenJudge上看看原题……
题目描述简直极其恶心,可以让你随时吐出来,本着大无畏的精神,我们分析一下题目:
1.S E :这两个点是迷宫问题最基本的要素,完全可以忽略不计
2.# . :这两种元素也是同上,见怪不怪了……
3.0-4 :这是本题坑点之一,每种钥匙都极其恶心,可能有相同的钥匙是恶心来源之一,最主要的是判断是否拥有目标把钥匙,恶心至极
4.$ :题目的巨坑,可以多次传送让主角可以自由穿越墙面拿取钥匙然后再传送回来,无法标记vis(因为可能会被再次使用),是比钥匙更恶心的存在
好吧,分析完后开始想对策……
首先,可以一眼看出使用广搜(bfs),那么接下来怎么办?钥匙怎么解决?不会用数组来标记吧?我一开始还真是弄了一个队列数组,但后来很难处理,所以不得不抛弃数组……我们可以发现:0-4可以巧用二进制来记录收集的宝石(比如:1和2两个宝石为2+2*2=6,0和1为1+2=3,0和4为1+2*2*2*2=17),可以巧妙的解决这个问题,标记数组vis开成三维即可。好吧,既然这样,我们再来思考一下如何传送。可以看出,传送门不需要时间传送,所以走到一个传送门,就相当于走到了所有传送门,那么就简单了……不过不要忘了恢复现场哦,代码如下:
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
queue<int>X;
queue<int>Y;
queue<int>D;
queue<int>Sum;
int t,n,m,k,sx,sy,fx,fy,f;
char S[205][205];
int vis[205][205][50];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
bool check(int x,int y,int l)
{
if(x<1||y<1||x>n||y>m)
{
return 0;
}
if(S[x][y]>='0'&&S[x][y]<='4')
{
int h=pow(2,S[x][y]-'0');
if(!vis[x][y][l+h])
return 1;
}
if(S[x][y]=='#'||vis[x][y][l])
{
return 0;
}
return 1;
}
void bfs()
{
while(!X.empty())
{
int x=X.front(),y=Y.front(),d=D.front(),sum=Sum.front(),num=0;
if(d>=16)
{
num++;
}
if(d%16>=8)
{
num++;
}
if(d%8>=4)
{
num++;
}
if(d%4>=2)
{
num++;
}
if(d%2>=1)
{
num++;
}
for(int i=0;i<4;i++)
{
int xx=x+dir[i][0],yy=y+dir[i][1];
if(check(xx,yy,d))
{
if(xx==fx&&yy==fy&&num>=k)
{
f=1;
printf("%d\n",sum+1);
return;
}
if(S[xx][yy]>='0'&&S[xx][yy]<='4')
{
int o=pow(2,S[xx][yy]-'0');
if(d%(o*2)<o)
{
X.push(xx);
Y.push(yy);
D.push(d+pow(2,S[xx][yy]-'0'));
Sum.push(sum+1);
vis[xx][yy][d+1]=1;
continue;
}
}
if(S[xx][yy]=='$')
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if((i!=xx||j!=yy)&&S[i][j]=='$'&&vis[i][j][d]==0)
{
vis[i][j][d]=1;
X.push(i);
Y.push(j);
D.push(d);
Sum.push(sum+1);
}
}
}
}
X.push(xx);
Y.push(yy);
D.push(d);
Sum.push(sum+1);
vis[xx][yy][d]=1;
}
}
X.pop();
Y.pop();
D.pop();
Sum.pop();
}
}
int main()
{
scanf("%d",&t);
for(;t;t--)
{
scanf("%d %d %d\n",&n,&m,&k);
while(!X.empty())
{
X.pop();
Y.pop();
Sum.pop();
D.pop();
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
S[i][j]=getchar();
if(S[i][j]=='S')
{
vis[i][j][0]=1;
sx=i;
sy=j;
X.push(i);//纵坐标
Y.push(j);//横坐标
D.push(0);//收集的宝石数据化
Sum.push(0);//行走的步数
}
if(S[i][j]=='E')
{
fx=i;
fy=j;
}
}
getchar();
}
bfs();
if(!f)
{
printf("oop!\n");
}
memset(vis,0,sizeof(vis));
memset(S,0,sizeof(S));
f=0;
}
}
嗯嗯嗯……不要无视最后的文字,有什么不懂的请在下方评论问我哦~