题目意思:说有一个人在(1,1) 他的目标点在(n,m) 每次是4方向的移动;
限制条件:有的各自之间有墙 或者门,强不可通过,有对应的要钥匙可以开启这个类型的所有门;
问题:求最少步骤数(和);
类似于poj 2935;
解:很明显的搜索 只要建图弄得好就非常好写:我还是 很推荐自己的建图 方法,不经常建图的可以看一看:(特别是 一个地方可以有多种钥匙,一开始我就Wa了)
#include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <cstdlib> #include <iostream> using namespace std; const int maxn=50*50*(1<<10)+10; bool flag[50][50][(1<<10)+10]; struct info { int x,y,S,ans; info (){} info(int x,int y,int S,int ans):x(x),y(y),S(S),ans(ans){} void input() { scanf("%d%d",&x,&y); } void FLAG() { flag[x][y][S]=true; } }; int n,m,p; int Map[51][51]; int direct[51][51][4]; info que[maxn]; const int dd[][2]={1,0,-1,0 ,0,-1,0,1}; bool jude(int & x,int & y) { return x>=1&&y>=1&&x<=n&&y<=m; } void inint() { memset(direct,0,sizeof direct); memset(Map,0,sizeof Map); memset(flag,false,sizeof flag); } void work() { info a,b; a.input();b.input(); int key; scanf("%d",&key); for(int i=0;i<4;i++) { if((a.x+dd[i][0]==b.x) && (a.y+dd[i][1]==b.y)) { direct[a.x][a.y][i]= (key==0 ? -1:key); direct[b.x][b.y][i^1]=(key==0 ? -1:key); break; } } } bool ok(const info & tmp,const int &i) { if(direct[tmp.x][tmp.y][i] == 0) return true; if(direct[tmp.x][tmp.y][i] == -1) return false; return ( 1<<(direct[tmp.x][tmp.y][i]-1) ) & tmp.S; } int solve() { int l,r;l=r=0; que[r++]=info(1,1,Map[1][1],0); while(l<r) { info tmp=que[l++]; if(tmp.x==n&&tmp.y==m) return tmp.ans; for(int i=0;i<4;i++) { if( !ok(tmp,i) ) continue; int x=tmp.x+dd[i][0]; int y=tmp.y+dd[i][1]; if(!jude(x,y)) continue; info t=info(x,y ,tmp.S|Map[x][y],tmp.ans+1); if(!flag[x][y][t.S]) { que[r++]=t; t.FLAG(); if(t.x==n&&t.y==m) return t.ans; } } } return -1; } int main() { while(~scanf("%d%d%d",&n,&m,&p)) { inint(); scanf("%d",&p); for(int i=1;i<=p;i++) work(); scanf("%d",&p); for(int i=1;i<=p;i++){ int x,y,key; scanf("%d%d%d",&x,&y,&key); Map[x][y]|=(1<<(key-1)); } printf("%d\n",solve()); } return 0; }
时间: 2024-11-08 22:45:06