题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=1091
题意:
在一个5*5的棋盘上,
放着12个黑骑士,12个白骑士。
骑士遵循国际象棋走法。
问至少经过几步可以将棋盘变成下面这样:
若10步以内无法达成,则视为无解。
算法:
我是用A*做的。
令g[]=不在自己的合法区域的骑士数。
然后状态压缩是用的二进制,单独保存空格的位置。
代码如下:
#include<cstdio> #include<iostream> #include<algorithm> #include<sstream> #include<cstdlib> #include<cstring> #include<string> #include<climits> #include<cmath> #include<queue> #include<vector> #include<stack> #include<set> #include<map> #define INF 0x3f3f3f3f #define eps 1e-8 using namespace std; typedef pair<int,int> PII; typedef pair<PII,PII > PIIII; #define st first #define nd second #define mp make_pair int dx[]= {1,1,-1,-1,2,2,-2,-2}; int dy[]= {2,-2,2,-2,1,-1,1,-1}; char mm[10][10]; struct cmp { bool operator()(const PIIII& a,const PIIII& b) { return a.nd.st+a.nd.nd>b.nd.st+b.nd.nd; } }; priority_queue<PIIII,vector<PIIII >,cmp> q; int get_id(int x, int y) { return 5*x+y; } int cal(int state, int s) { int cot=0; for(int i=0; i<25; i++) { if(i==s) { continue; } int x=i/5; int y=i%5; if(state&(1<<i)) { if(y<x||(x==y&&x>=2)) { cot++; } } else { if (y>x||(x==y&&x<=2)) { cot++; } } } return cot; } int main() { int cas; scanf("%d",&cas); while(cas--) { int ans=-1; int state=0; int s; for(int i=0; i<5; i++) { scanf("%s",&mm[i]); } for(int i=0; i<25; i++) { int x=mm[i/5][i%5]-'0'; if(x==2) { s=i; x=0; } state|=x<<i; } while(!q.empty()) { q.pop(); } int f=0; int g=cal(state,s); if(f+g<=10) { q.push(mp(mp(state,s),mp(f,g))); } while(!q.empty()) { int state=q.top().st.st; int s=q.top().st.nd; int f=q.top().nd.st; int g=q.top().nd.nd; if(!g) { ans=f; break; } q.pop(); int x=s/5; int y=s%5; for(int i=0; i<8; i++) { int nx=x+dx[i]; int ny=y+dy[i]; if(nx<0||nx>=5||ny<0||ny>=5) { continue; } int ns=get_id(nx,ny); int nstate=state&(~(1<<ns)); if(state&(1<<ns)) { nstate|=1<<s; } int nf=f+1; int ng=cal(nstate,ns); if(nf+ng<=10) { q.push(mp(mp(nstate,ns),mp(nf,ng))); } } } if(ans==-1) { puts("Unsolvable in less than 11 move(s)."); } else { printf("Solvable in %d move(s).\n",ans); } } return 0; }