A*
P1379 Wah Rong Road
The problem is to use the minimum number of steps from the initial layout to the target layout. Each time you can only move the grid around 0, which is Huarong Road;
How to solve it using algorithmic ideas?
State compression ideas
Each number represents the current state. Both the queue and map functions record the current state number.
Describing a state has a matrix form and a numerical form
Here c[3][3] is the matrix describing the state, and n is the number describing the state.
Here, n is converted into matrix form, and the position of 0 in the matrix is obtained, recorded with f and g.
The exchange operation cannot be performed in numbers and is relatively abstract, so it is necessary to convert it into a matrix, try the exchange in the matrix, and then convert it back to the form of numbers for storage after the exchange is completed, in order to save space. ns means that the current matrix is moved according to the current traversal order. The final result is,
If it does not appear in the Map, it means that this number (this state) does not exist in the Map, which means it is a newly arrived state. Since it is bfs, it must be the minimum number of steps to reach this state.
#include<iostream> #include<map> #include<queue> #include<algorithm> #define ll long long//I saw a very cool operation here: directly define int as long long; the main function uses signed type - Mom is no longer afraid that I forget to open long long! using namespace std; const ll dx[]={-1,0,0,1},dy[]={0,-1,1,0};//Transfer array; ll n; int main() { cin>>n; queue<ll> q; q.push(n); map<ll,ll> m; m[n]=0; while(!q.empty()) { int u=q.front(); //Initial state is queued int c[3][3],f=0,g=0,n=u;q.pop(); if(u==123804765)break; for(ll i=2;i>=0;i--) for(ll j=2;j>=0;j--) { c[i][j]=n ,n/=10; if(!c[i][j])f=i,g=j; } for(ll i=0;i<4;i + + ) { ll nx=f + dx[i],ny=g + dy[i],ns=0; if(nx<0||ny<0||nx>2||ny>2)continue; //out of bounds will not be executed swap(c[nx][ny],c[f][g]); for(ll i=0;i<3;i + + ) for(ll j=0;j<3;j + + )ns=ns*10 + c[i][j];//Matrix to sequence if(!m.count(ns)) { m[ns]=m[u] + 1; //map removes duplicates and counts the number of steps required to reach this state. q.push(ns); } swap(c[nx][ny],c[f][g]);//State restoration } } cout<<m[123804765]<<endl; // The subscript of the map is directly represented by the sequence return 0; }
map
map search
map operation function
The commonly used count() returns the number of occurrences, int type, returns the number of occurrences of the key, not the value corresponding to the key, so it can only be 0 or 1
If it is !m.count(n), it means that it is triggered when it is not found, that is, there is no key n in the map at this time.
m.count(n) means that this element has been found, that is, there is already n element in the map.
A* method
This step is to determine whether the current state is still a possible solution. step is the current step number, cnt is the valuation function value. The determination of the value of cnt involves a double cycle. Once it is detected that the solution in the current grid is different, It will + + cnt, this loops 9 times, or if it exceeds the limit while in the loop, it will exit.
This is to determine whether the current solution is
That is to say, pre is to record the last time you came here The direction mark at the time means that you should not go back. If you do, go up (down) first and then down (up). Go left (right) first and then right (left).
The state movement array can be manually defined so that the sequence numbers in opposite directions have a certain relationship.
Here is a symmetric array arrangement, Thus, the sum of the serial numbers in the opposite direction is the array length – 1
Therefore, in the recursive judgment, it is necessary to judge pre + i==3, pre is the previous direction, and i is the direction selected this time. If the sum is 3, it means that we have gone back and need to be cut off.
Although this operation cannot avoid the birth of infinite loops, such as back-shaped loops, or the emergence of repeated states (avoiding repeated states that only require two steps, but may return to the initial position in multiple steps), it can still avoid a large number of two-steps. repeat
Here is the input string (status compression sequence) into a matrix and get the position of 0
K is used as the outer loop, that is, it is directly based on the step limit to determine whether it can be reached currently.
#include<iostream> #include<string> #include<map> #include<cmath> #include<algorithm> #include<queue> #include<cstring> #include<cstdio> using namespace std; typedef long long <; int read() { int f=1,x=0; char ss=getchar(); while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();} while(ss>='0' & amp; & amp;ss<='9'){x=x*10 + ss-'0';ss=getchar();} return f*x; } char ss[15]; int ans[4][4]= {<!-- -->{0,0,0,0}, {0,1,2,3}, {0,8,0,4}, {0,7,6,5}}; int a[5][5],k,judge; int nxtx[]={0,1,-1,0}; int nxty[]={1,0,0,-1}; int check() { for(int i=1;i<=3; + + i) for(int j=1;j<=3; + + j) if(ans[i][j]!=a[i][j])return 0; return 1; } int test(int step) { int cnt=0; for(int i=1;i<=3; + + i) for(int j=1;j<=3; + + j) if(ans[i][j]!=a[i][j]){ if( + + cnt + step>k) return 0;} return 1; } void A_star(int step,int x,int y,int pre) { if(step==k){ if(check())judge=1; return;}The maximum depth of the current limit is reached if(judge) return; for(int i=0;i<4; + + i) { int nx=x + nxtx[i],ny=y + nxty[i]; if(nx<1||nx>3||ny<1||ny>3||pre + i==3) continue; //Added the above optimal pruning swap(a[x][y],a[nx][ny]); if(test(step) & amp; & amp;!judge) A_star(step + 1,nx,ny,i);//A* valuation is legal and then search downwards swap(a[x][y],a[nx][ny]); } } int main() { int x,y; scanf("%s", & amp;ss); for(int i=0;i<9; + + i) { a[i/3 + 1][i%3 + 1]=ss[i]-'0'; if(ss[i]-'0'==0)x=i/3 + 1,y=i%3 + 1; } if(check()){printf("0");return 0;}//Special judgment does not require movement while( + + k)//Enumeration maximum depth { A_star(0,x,y,-1); if(judge){printf("%d",k);break;} } return 0; }