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\n");
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\n");
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 }

猜你喜欢

转载自www.cnblogs.com/guapisolo/p/10008175.html