• 八数码问题/搜索小结


    cdcq讲的挺好的其实。之所以没有回应是因为真的想不出了。

    八数码问题

    这个问题可以用BFS和A*解决。

    BFS

    考虑按空格的位置搜索,每次操作相当于移动空格。

    此处需要记忆化,不然会T飞。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cstring>
     5 #include<queue>
     6 #include<map>
     7 using namespace std;
     8 int n;
     9 int c[4][4];
    10 queue<int> q;
    11 map<int,int> mp;
    12 
    13 int k[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
    14 
    15 inline bool check(int x,int y){
    16     if(x<1||x>3||y<1||y>3)return false;
    17     return true;
    18 }
    19 
    20 inline int rebiu(){
    21     int ans=0;
    22     for(int i=1;i<=3;i++)
    23         for(int j=1;j<=3;j++)
    24         ans=ans*10+c[i][j];
    25     return ans;
    26 }//将矩阵转化成数 
    27 
    28 inline void bfs(int now){
    29     q.push(now);
    30     mp[now]=0;
    31     while(!q.empty()){
    32         int lr,ud;//存储空格的位置 
    33         int x=q.front();q.pop();
    34         if(x==123804765){
    35             break;
    36         }
    37         int shp=x;
    38         for(int i=9;i>=1;--i){
    39             int k=shp%10;shp/=10;
    40             c[(i-1)/3+1][((i-1)%3)+1]=k;
    41             if(k==0) ud=(i-1)/3+1,lr=((i-1)%3)+1;
    42         }//恢复成矩阵,swap要用的 
    43         
    44         for(int i=0;i<4;++i){
    45             int dx=ud+k[i][0],dy=lr+k[i][1];
    46             if(!check(dx,dy))continue;
    47             swap(c[ud][lr],c[dx][dy]);
    48             int val=rebiu();
    49             if(!mp.count(val))
    50             mp[val]=mp[x]+1,
    51             q.push(val);
    52             swap(c[ud][lr],c[dx][dy]);
    53         }
    54     }
    55     
    56 }
    57 
    58 
    59 int main(){
    60     scanf("%d",&n);
    61     bfs(n);
    62     cout<<mp[123804765];
    63 }

    双向BFS

    双向BFS的特点:当前状态和目标状态都明确。

    双向BFS大大降低了搜索层数,所以快的飞起。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cstring>
     5 #include<queue>
     6 #include<map>
     7 using namespace std;
     8 int n;
     9 int c[4][4];
    10 map<int,int> v;//被哪个点扫到 
    11 map<int,int> ans;
    12 queue<int> q;
    13 int finl;
    14 int end=123804765;
    15 int dr[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
    16 
    17 inline int rebiu(){
    18     int ans=0;
    19     for(int i=1;i<=3;i++)
    20         for(int j=1;j<=3;j++)
    21         ans=ans*10+c[i][j];
    22     return ans;
    23 }
    24 
    25 inline void bfs(int now){
    26     int flag=0;
    27     if(now==end)return;
    28     q.push(now);q.push(end);
    29     v[now]=1;v[end]=2;ans[now]=0;ans[end]=1;//ans[end]是要等于1的。 
    30     while(!q.empty()){
    31         int x=q.front();q.pop();
    32         int k=x,px,py;
    33         for(int i=9;i>=1;i--){
    34             c[(i-1)/3+1][(i-1)%3+1]=k%10;
    35             if(k%10==0)px=(i-1)/3+1,py=(i-1)%3+1;
    36             k/=10;
    37         }
    38         for(int i=0;i<4;i++){
    39             int dx=px+dr[i][0],dy=py+dr[i][1];
    40             if(dx<1||dy<1||dx>3||dy>3)continue;
    41             swap(c[dx][dy],c[px][py]);
    42             int val=rebiu();
    43             if(v[val]==v[x]){
    44                 swap(c[dx][dy],c[px][py]);
    45                 continue;
    46             }//利用v顺便记忆化一下 
    47             if(v[val]+v[x]==3){
    48                 finl=ans[val]+ans[x];
    49                 flag=1;break;
    50             }//两个不同类型相遇 就是答案 
    51             v[val]=v[x],ans[val]=ans[x]+1;
    52             q.push(val);
    53             swap(c[dx][dy],c[px][py]);
    54         }
    55         if(flag)break;
    56     }
    57 }
    58 
    59 
    60 int main(){
    61     scanf("%d",&n);
    62     bfs(n);
    63     cout<<finl;
    64 }

    A*

    对于一个状态n, 经过n的答案 f* [ n ] = g* [ n ] + h* [ n ].

    g*表示从出发点到n,h*表示从n到终点。

    我们可以设置估价函数 f [ n ] = g [ n ] + h [ n ]

    h是我们对未来的预估,且 h [ n ] <=h* [ n ]

    这样可以保证求出最优解且h越大跑的越快。

    对于一个题有多种估价方式,只要正确,大胆跑就完事了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cstring>
     5 #include<map>
     6 using namespace std;
     7 int n;
     8 int brd=0;
     9 int c[4][4];
    10 int finl[4][4]={{0,0,0,0},{0,1,2,3},{0,8,0,4},{0,7,6,5}};
    11 int dr[4][2]={{0,1},{1,0},{-1,0},{0,-1}};//方向需要特殊排列一下 
    12 int px,py;
    13 int flag=0;
    14 int k=1;
    15 inline bool lok(int s){
    16     int dif=0;
    17     for(int i=1;i<=3;i++)
    18         for(int j=1;j<=3;j++)
    19             if(c[i][j]!=finl[i][j]){
    20                 ++dif;
    21                 if(dif+s>k)return false;
    22             }
    23     return true;
    24 }/*估价函数可以更优。目前我知道最优的
    25 应该是每个点与目标位置的曼哈顿距离(不算空格
    26 因为空格位置在点移动过程中就改变了,不用另算) 
    27 */ 
    28 inline bool check(){
    29     for(int i=1;i<=3;i++)
    30         for(int j=1;j<=3;j++)
    31         if(c[i][j]!=finl[i][j])return false;
    32     return true;
    33 }
    34 
    35 inline void dfs(int x,int y,int s,int pre){
    36     if(s==k){
    37         if(check())flag=1;
    38         return;
    39     }
    40     if(flag)return;
    41     for(int i=0;i<4;i++){
    42         int dx=x+dr[i][0],dy=y+dr[i][1];
    43         if(dx<1||dx>3||dy<1||dy>3||i+pre==3)continue;//i+pre是为了防止搜回去,mp存状态T了 
    44         swap(c[dx][dy],c[x][y]);
    45         if(lok(s))
    46             dfs(dx,dy,s+1,i);
    47         swap(c[dx][dy],c[x][y]);
    48     }
    49 }
    50 
    51 int main(){
    52     scanf("%d",&n);
    53     if(n==123804765){
    54         printf("0");return 0;
    55     }
    56     for(int i=8;i>=0;i--){
    57         c[i/3+1][(i%3)+1]=n%10;
    58         if(n%10==0)px=i/3+1,py=(i%3)+1;
    59         n/=10;
    60     }
    61     while(k++){
    62         dfs(px,py,0,-1);
    63         if(flag){
    64             printf("%d",k);
    65             return 0;
    66         }
    67     }
    68 }

    IDA*

    在搜索深度不确定,目标状态不明确(有多解)时使用IDA* 。

    ID==迭代加深。

  • 相关阅读:
    Linux vim 入门 配置 及 使用初步
    Java网络编程之TCP通信
    [ javascript ] getElementsByClassName与className和getAttribute!
    找出二叉查找树中指定结点的”下一个&quot;结点(也即中序后继)
    DNS分别在什么情况下使用UDP和TCP
    高仿京东APP首页“京东快报”自己主动向上滚动的广告条
    HDU 5016 Mart Master II (树上点分治)
    Myeclipse10完美破解过程
    git format-patch 用法【转】
    Git下的冲突解决【转】
  • 原文地址:https://www.cnblogs.com/chiyo/p/11182186.html
Copyright © 2020-2023  润新知