【NOI OJ】 2.5 搜索 7221 拯救公主

来源:互联网 发布:剩菜 亚硝酸盐 知乎 编辑:程序博客网 时间:2024/04/29 12:38

    由于一些原因,本题无法把题目描述放上来,可以去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;}}

    嗯嗯嗯……不要无视最后的文字,有什么不懂的请在下方评论问我哦~

2 0
原创粉丝点击