HDU 6171 Admiral (DFS + 剪枝)

来源:互联网 发布:天干地支年算法 编辑:程序博客网 时间:2024/05/17 23:11

题意:

给出原始阵列

0

1 1

2 2 2

3 3 3 3

4 4 4 4 4

5 5 5 5 5 5

问对于给出的某种阵列,能否通过每步只移动 0 至(i - 1 , j)or ( i - 1 , j - 1)  or ( i + 1 ,  j ) or ( i + 1 , j  + 1 ) ,在20步之内移动到原始阵列。

思路:

考虑到只要求20步,直接搜索即可。

但 4 ^ 20 一定会 TLE 。考虑剪枝


显然的剪枝是,对于任意局面。

当且仅当 剩余步数 + 1 >= 非法位置的个数 时,有可行解

交上去仍然TLE


考虑到没有状态去重

但由于移动步伐诡异,剪去原地摩擦的情况就能得到很好的效果。

故对父节点做了访问去重。


貌似是数据较水的原因15MS水过。

正解是双向BFS O(4^10 * hash_status)

代码:

#include <bits/stdc++.h>using namespace std;int a[10][10],T,stx,sty;int dirx[]={-1,-1,1,1};int diry[]={-1,0,0,1};int ans;void dfs(int x,int y,int step,int left,int fax,int fay){    if(step>=ans||(ans-step)+1<left) return ;//剪枝1    if(left==0){        ans=step;        return ;    }    for(int i=0;i<4;i++){        int xx=x+dirx[i],yy=y+diry[i];        if(xx>=1&&xx<=6&&yy>=1&&yy<=xx){            if(xx==fax&&yy==fay) continue;//剪枝2 (原地摩擦的情况)            int shift=0;            int num=a[xx][yy];            if(num==xx) shift++;            else if(x==num) shift--;            if(x==1) shift++;            else if(xx==1) shift--;            swap(a[x][y],a[xx][yy]);            dfs(xx,yy,step+1,left+shift,x,y);            swap(a[x][y],a[xx][yy]);        }    }    return ;}int main(){    //freopen("in.txt","r",stdin);    scanf("%d",&T);    while(T--){        int left=0;        for(int i=1;i<=6;i++){            for(int j=1;j<=i;j++){                scanf("%d",&a[i][j]);a[i][j]++;                if(a[i][j]==1){                    stx=i;sty=j;                }                if(a[i][j]!=i) left++;            }        }        ans=21;        dfs(stx,sty,0,left,0,0);        if(ans==21){            puts("too difficult");        }else            printf("%d\n",ans);    }}

原创粉丝点击