• HDU 1043 Eight (A*算法)


    题目大意:裸的八数码问题,让你输出空格的一条合法移动路径

    首先利用康托展开对排列编号,可以预处理出排列,就不必逆展开了

    然后利用A*算法求解

    A*算法是一种启发式搜索,具体实现要用到优先队列/堆,不同于$dijkstra$,它的堆不是按照 初始状态当前状态的花费$dis_{i}$进行贪心转移,而是额外处理出一个估值函数,处理出当前状态目标状态花费的估计值$h_{i}$,然后按照$dis_{i}+h_{i}$排序,优先取出总和最小的。并且每个状态只会被搜索一次。如果搜索到了目标状态,立即跳出

    这个过程,相当于我们取出一个全局较优解,虽然不一定是最优的,但大量减少了无用的搜索时间

    而这道题的估值函数,可以粗略的计算为,每个数 当前状态的位置 到 目标状态的位置 的曼哈顿距离$(|xj-xi|+|yj-yi|)$ 之和

    经过了A*优化的搜索,虽然不一定能搜出最短的路径,但极大减少了搜索的时间,因为搜的路径越短,我们搜索的总时间也越短,几乎是指数级别的优化。

    然而A*也有弊端,如果存在无解的情况,A*就会退化成BFS,对所有状态都搜一次,而且多了一个常数$log$,在hdu上会T掉

    所以我上网查了用了八数码判无解的方法,即对于去掉空格以后的8个数的排列,如果逆序对数量总和是奇数,则无解

    证明大概是这样的,对于一个序列,任意交换两个相邻的数,逆序对数量的奇偶性不变,而八数码的表格扔到序列上,也满足这个性质

    搞了大半个下午终于过了

      1 #include <queue>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define NN 370010
      6 #define MM 100
      7 #define ll long long 
      8 #define uint unsigned int
      9 #define ull unsigned long long 
     10 #define inf 0x3f3f3f3f
     11 using namespace std;
     12 
     13 struct node{
     14     int id,d;
     15     friend bool operator<(const node &s1,const node &s2)
     16     {return s1.d>s2.d;}
     17     node(int id,int d):id(id),d(d){}
     18     node(){}
     19 };
     20 int xx[4]={-1,0,1,0},yy[4]={0,1,0,-1};
     21 int f[NN][11],vis[NN],p[5][5],cnt;
     22 int h[NN],g[NN],fa[NN],d[NN];
     23 int S[11],use[11],now[11],tmp[11],mu[11];
     24 inline int mabs(int x){return x>=0?x:-x;}
     25 char ans[MM],c[4]={'u','r','d','l'};
     26 
     27 void dfs_permu(int dep)
     28 {
     29     if(dep==10){
     30         cnt++;
     31         for(int i=1;i<=9;i++)
     32             f[cnt][i]=now[i],
     33             h[cnt]+=(mabs((i-1)/3-(now[i]-1)/3)+mabs((i-1)%3-(now[i]-1)%3));
     34         return;
     35     }
     36     for(int i=1;i<=9;i++)
     37         if(!use[i]){
     38             use[i]=1,now[dep]=i;
     39             dfs_permu(dep+1);
     40             use[i]=0,now[dep]=0;
     41         }
     42 }
     43 bool check(int x,int y)
     44 {if(x<1||y<1||x>3||y>3)return 0;return 1;}
     45 void Pre()
     46 {
     47     dfs_permu(1);
     48     mu[1]=1;
     49     for(int i=2;i<=9;i++)
     50         mu[i]=mu[i-1]*i;
     51 }
     52 int s[100];
     53 void update(int x,int w){for(int i=x;i<=9;i+=(i&(-i)))s[i]+=w;}
     54 int query(int x){int ans=0;for(int i=x;i>0;i-=(i&(-i)))ans+=s[i];return ans;}
     55 int canter(int *tmp)
     56 {
     57     int ans=0;
     58     for(int i=1;i<=9;i++)
     59         update(i,1);
     60     for(int i=1;i<=9;i++){
     61         ans+=query(tmp[i]-1)*mu[9-i];
     62         update(tmp[i],-1);
     63     }
     64     return ans+1;
     65 }
     66 int clr[NN],nn;
     67 void init()
     68 {
     69     memset(ans,0,sizeof(ans));
     70     for(int i=1;i<=nn;i++){
     71         vis[clr[i]]=fa[clr[i]]=d[clr[i]]=0;
     72         g[clr[i]]=inf;
     73     }nn=0;
     74 }
     75 
     76 int main()
     77 {
     78     Pre();
     79     char str[10];
     80     priority_queue<node>q;
     81     nn=cnt;
     82     for(int i=1;i<=nn;i++) clr[i]=i;
     83     while(scanf("%s",str)!=EOF)
     84     {
     85     
     86     if('1'<=str[0]&&str[0]<='8')
     87         S[1]=str[0]-'0';
     88     else S[1]=9;
     89     for(int i=2;i<=9;i++)
     90     {
     91         scanf("%s",str);
     92         if('1'<=str[0]&&str[0]<='8')
     93             S[i]=str[0]-'0';
     94         else S[i]=9;
     95     }
     96     int invcnt=0;
     97     for(int i=1;i<=9;i++)
     98         for(int j=1;j<i;j++){
     99             if(S[i]==9||S[j]==9) continue;
    100             if(S[j]>S[i]) invcnt++;
    101         }
    102     if(invcnt&1){
    103         printf("unsolvable
    ");
    104         continue;}
    105     init();
    106     int s,t,st,sx,sy,x,y;
    107     st=canter(S);
    108     if(st==1){
    109         puts("");
    110         continue;
    111     }
    112     q.push(node(st,h[st]));
    113     g[st]=0;
    114     while(!q.empty())
    115     {
    116         node k=q.top();q.pop();
    117         s=k.id;clr[++nn]=s;
    118         if(s==1) break;
    119         if(vis[s]) continue; vis[s]=1;
    120         for(int i=1;i<=9;i++)
    121             if(f[s][i]==9)
    122                 sx=(i-1)/3+1,sy=(i-1)%3+1;
    123         for(int i=1;i<=9;i++)
    124             tmp[i]=f[s][i];
    125         for(int k=0;k<4;k++)
    126         {
    127             x=sx+xx[k],y=sy+yy[k];
    128             if(!check(x,y)) continue;
    129             swap(tmp[(x-1)*3+y],tmp[(sx-1)*3+sy]);
    130             int t=canter(tmp);
    131             if(g[t]>g[s]+1&&!vis[t]){
    132                 g[t]=g[s]+1,fa[t]=s,d[t]=k;
    133                 q.push(node(t,g[t]+h[t]));
    134             }
    135             swap(tmp[(x-1)*3+y],tmp[(sx-1)*3+sy]);
    136         }
    137     }
    138     while(!q.empty()){
    139         node k=q.top();q.pop();
    140         s=k.id;clr[++nn]=s;
    141     }
    142     if(!fa[1]){
    143         printf("unsolvable
    ");
    144         continue;
    145     }
    146     t=1;int num=0;
    147     while(t!=st){
    148         ans[++num]=c[d[t]];
    149         t=fa[t];
    150     }
    151     for(int i=num;i>=1;i--)
    152         printf("%c",ans[i]);
    153     puts("");
    154     
    155     }
    156     
    157     return 0;
    158 }
  • 相关阅读:
    win10 L2TP拨号
    Esxi直通板载Sata
    Esxi 增加网卡驱动 生成ISO
    IPMITOOL THRESHOLD 修改
    Reverse Engineering Supermicro IPMI
    Esxi通过RDM直通硬盘
    Centos 安装后优化
    Centos 6安装apache 2.4
    Try Catch Finally 中Finally的代码在什么时候不被执行
    用CutePDF AND GhostScript 生成PDF的处理流
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10008175.html
Copyright © 2020-2023  润新知