在一个8*8的棋盘上摆上8个皇后,要求对这些皇后进行移动,最后使得这8个皇后不能相互直接攻击到,问最少要对这些皇后移动多少次。
注:皇后每移动一次能沿竖直,水平,对角线方向移动任意步数,攻击方式同移动方式。
输入
输入共8行,每行8个字符’.’表示空格子,’q’表示该位置有皇后占据。
输出
输出最少移动的总步数。
思路:
1、首先dfs枚举出满足条件的92种方案。
2、当前的棋盘状态移动到92种方案的最小移动的步数。
问题:怎么解决某个点移动到另一个点的步数?
(1)同行同列0 步(2)同行不同列 1 步 (3)同列不同行 1 步(4)在同一斜线上 1 步(5)剩下的情况 2步
需要考虑,假如移动过程中有障碍咋办?
(1)移到指定位置中间有棋子,可以先将该棋子移走再移本棋子。
(2)移的目的位置有棋子占领,可以先将该棋子移走再移本棋子
也就是通过交换移的顺序可以解决此问题,而没有影响移的步数。
因为棋子间不能同行同列,也不会同时存在(1)(2)两种情况。
状态:dp[i][j]为移动前i个棋子,状态为j的最小步数。
dp[i][j|(1<<k)]=min(dp[i][j|(1<<k)],dp[i][j]+num[i][k]); k为当前的第i行放的位置,前提是之前没有放在第k列。
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
struct node{
int x,y;
};
char c;
node aim[10],sor[10];
int vis[10],cros1[20],cros2[20],num[10][10],dp[10][1<<9],ans,cnt,t,k;
int ma[10][10];
int getstep(int i, int j){//目标行为i,当前为j行
if(aim[i].x==sor[j].x&&aim[i].y==sor[j].y) return 0;//同行同列
if(aim[i].x==sor[j].x&&aim[i].y!=sor[j].y) return 1;//同行不同列
if(aim[i].x!=sor[j].x&&aim[i].y==sor[j].y) return 1;//不同列同行
if(abs(aim[i].x-sor[j].x)==abs(aim[i].y-sor[j].y)) return 1;//同一斜线
return 2; //不同行不同列也不同斜线,2步即可
}
void solve(){
for(int i=0; i<8; i++){
for(int j=0; j<8; j++){
num[i][j]=getstep(i,j);//计算两个点移动的最步数小
}
}
memset(dp,0x3f3f3f3f,sizeof(dp));
dp[0][0]=0;//在0行状态为0时最小走0步
for(int i=0; i<8; i++){//行
for(int j=0; j<(1<<8); j++)//状态
{
if(dp[i][j]==0x3f3f3f3f) continue;
for(int p=0; p<8; p++){//每行的位置
if(j&(1<<p)) continue;//该列已经使用了
dp[i+1][j|(1<<p)]=min(dp[i+1][j|(1<<p)],dp[i][j]+num[i][p]);
}
}
}
ans=min(ans,dp[8][(1<<8)-1]);
}
void dfs(int x){//dfs 92种可行方案
if(x==8){
solve();
return;
}
for(int y=0; y<8; y++){
if(!vis[y]&&!cros1[8-y+x]&&!cros2[x+y+1]){
vis[y]=cros1[8-y+x]=cros2[x+y+1]=1;
sor[x].x=x; sor[x].y=y;
dfs(x+1);
vis[y]=cros1[8-y+x]=cros2[x+y+1]=0;
}
}
}
int main()
{
int cas=1;
cin>>t;
while(t--){
cnt=0;
ans=0x7fffffff;
for(int i=0; i<8; i++){
for(int j=0; j<8; j++){
cin>>c;
if(c=='q'){
aim[cnt].x=i;
aim[cnt++].y=j;
}
}
}
memset(vis,0,sizeof(vis));
memset(cros1,0,sizeof(cros1));
memset(cros2,0,sizeof(cros2));
dfs(0);
cout<<"Case "<<cas<<": "<<ans<<endl;
cas++;
}
return 0;
}