1. 程式人生 > >胡搞-強化版的light oj-1055-的思路-AI版的6重暴力For循環的BFS

胡搞-強化版的light oj-1055-的思路-AI版的6重暴力For循環的BFS

數量 front deb style num void 組成 gpo 隊列優化

新題目大意:

  三個棋子按照先後順序,可以隨意方向合法地走到空位置上(而不是像原題light oj-1055中的一樣三個棋子每次走的方向都一致),當三個棋子全部走進目標地點,就結束;求需要指揮的最少次數。

思路:

  BFS

  在每次進行指揮時,需要分別指揮三個棋子,每個棋子至多有五種走法(第五種為原地不動——因為前進時受阻沒法動的時候),同時枚舉三個棋子的當前位置進入隊列中。由於每個棋子在走的時候會影響到後續的點的移動,故需要三重for循環來枚舉每次三個點的移動先後順序,然後依舊三重循環來枚舉搞定三個點的移動方向,然後判斷-標記-加入隊列?結束。

標記去重的BFS思路:   三個棋子共同組成的局面可以不分先後相互等價;用vis[A.x][A.y][B.x][B.y][C.x][C.y]來進行標記!   所以對於每一個局面,都有其余5個分先後的局面與其等價。即ABC=ACB=BAC=BCA=CAB=CBA. /* 4 ..A. XXXB ..C. .... /*或許可以再加一個優先隊列優化一下時間:排序標準是三個點與三個終點的最小距離之和;或許還可以再加一個剪枝的方法:每次搜索一個點時需要枚舉四個方位,可以事先統計所有空點周圍不是的‘#’的方向數量,當每個點可以作出的選擇數等於上述點數就continue。*/ //下面 極大值測試3.9s(Tmax==50), 1 9 AB....C.. ......... ......... ......... ......... ......... ......... ......... X..X..X.. */ 胡搞的代碼: 技術分享圖片
#define 其余頭文件...
#define N 10
#define inf 0x3f3f3f3f
char mp[N][N];
int n;
struct node{
    int x,y;
}just;
struct group{//一個局面三個點的位置,位置之間等價
    node p[3];//0,1,2三位有效存儲
    int step;
}st;
int dir[5][2]={{0,0},{1,0},{0,1},{0,-1},{-1,0} };
bool vis[N][N][N][N][N][N];//標記數組,模擬每一組棋子組合成的局面
bool judge_end(group x){  //判斷當前局面是否達到結束要求
int num=0; for(int i=0;i<3;i++){ if(mp[x.p[i].x][x.p[i].y]==X) num++; } if(num==3)return true; return false; } void getvis(group a){//從一個局面獲取6個標記 vis[a.p[0].x][a.p[0].y][a.p[1].x][a.p[1].y][a.p[2].x][a.p[2].y]=true; vis[a.p[0].x][a.p[0].y][a.p[2].x][a.p[2
].y][a.p[1].x][a.p[1].y]=true; vis[a.p[1].x][a.p[1].y][a.p[0].x][a.p[0].y][a.p[2].x][a.p[2].y]=true; vis[a.p[1].x][a.p[1].y][a.p[2].x][a.p[2].y][a.p[0].x][a.p[0].y]=true; vis[a.p[2].x][a.p[2].y][a.p[1].x][a.p[1].y][a.p[0].x][a.p[0].y]=true; vis[a.p[2].x][a.p[2].y][a.p[0].x][a.p[0].y][a.p[1].x][a.p[1].y]=true; } bool getstep(int i,int k,group a){//i表示第i個點的下一步操作,向dir[k]進行下一步 node s=a.p[i]; s.x=s.x+dir[k][0]; s.y=s.y+dir[k][1]; if(s.x>=n||s.y>=n||s.x<0||s.y<0)return false;//越界,‘#’,走到同一局面其他點上, false if(mp[s.x][s.y]==#)return false; for(int j=0;j<=2;j++){ if(i!=j&&(a.p[j].x==s.x)&&(a.p[j].y==s.y)) return false; } just=s;//存儲的全局變量 return true; } void debug(group a){ printf("*%dstep* *A*(%d,%d) ",a.step,a.p[0].x,a.p[0].y); printf("*B*(%d,%d) ",a.p[1].x,a.p[1].y); printf("*C*(%d,%d)\n",a.p[2].x,a.p[2].y); } int bfs(){ memset(vis,false,sizeof(vis)); group now,ne,ne2,ne3; queue<group>Q; st.step=0; Q.push(st); //標記起點局面 getvis(st); while(Q.size()){ now=Q.front(); Q.pop(); if(judge_end(now))return now.step; //按ABC,ACB,BAC,BCA,CAB,CBA六種先後方式來枚舉,i-j-k三重循環 for(int i=0;i<3;i++){//枚舉第一個先走的編號 for(int j=0;j<3;j++){//枚舉第二個編號 for(int k=0;k<3;k++){//第三個 if(j==i||i==k||j==k)continue; for(int x=0;x<5;x++){ //x-y-z三種循環分別表示i-j-k的走位方向 ne=now; if(getstep(i,x,ne)==false)continue; else ne.p[i]=just; for(int y=0;y<5;y++){ ne2=ne; if(getstep(j,y,ne2)==false)continue; else ne2.p[j]=just; for(int z=0;z<5;z++){ ne3=ne2; if(getstep(k,z,ne3)==false)continue; else ne3.p[k]=just; //在這裏得到了合格的next3局面,然後進行判斷 if(vis[ne3.p[0].x][ne3.p[0].y][ne3.p[1].x][ne3.p[1].y][ne3.p[2].x][ne3.p[2].y]==true) continue;//重復走過了 ne3.step=now.step+1; // debug(ne3); getvis(ne3);//進行標記 if(judge_end(ne3)){ // printf("--up|------now :");debug(now); return ne3.step; } else Q.push(ne3); } } } } } } } return -1; } int main() { int T,cas=0; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=0;i<n;i++)//讀圖 scanf("%s",mp[i]); int num1=0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(mp[i][j]>=A&&mp[i][j]<=C) st.p[num1].x=i,st.p[num1++].y=j; } } printf("Case %d: ",++cas); int ans=bfs(); if(ans!=-1) printf("%d\n",ans); else printf("trapped\n"); } return 0; }
View Code

胡搞-強化版的light oj-1055-的思路-AI版的6重暴力For循環的BFS