lightoj 1061 - N Queen Again

Given an 8 x 8 chess board where 8 queens are placed in any arbitrary order. You want to move the queens such that no one attacks each other.

In each move you can move a queen as in normal chess. That means you can move a queen vertically, horizontally or diagonally. And you can move it to multiple cells at a time but the direction can't be changed and you can't jump over any other queen. Now you want to find the minimum number of moves to do this.

Input

Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case contains a blank line and an 8 x 8 board consisting of '.' and exactly eight 'q''.' stands for empty position and 'q' stands for a queen.

Output

For each case, output the case number and minimum number of queen moves you have to do such that no queen attacks another.

Sample Input

Output for Sample Input

2

 

q.......

.q......

..q.....

...q....

....q...

.....q..

......q.

.......q

 

.......q

.......q

........

...q..q.

.q...q..

....q...

..q.....

........

Case 1: 7

Case 2: 5



这题的大意是给你一个8*8的棋盘,上面任意地摆放着8个皇后,问你最少走多少步,才能让这些皇后不能相互攻击。

皇后的走法是沿着横线竖线对角线可以一直走(中国象棋中车的加强版。。。)。

这题的思路是先处理出来8皇后的所有种摆法,一共92种,然后再用记忆化搜索找出需要走到步数。

dp[i][j]表示i个棋子在j状态下已经摆放到规定的位置上去的需要的步数。

题目里还有一个条件,就是皇后在走的时候不能跨越其他的皇后,其实这个条件无关紧要,下面是大牛的证明:

1。如果要移动该子到相应位置时,有一个还没有移动到相应位置的棋子卡位了,那么就让那个卡位的棋子先移动,再移动该棋子,步数不变 
2。如果要移动该子到相应位置时,有一个已经移动到相应位置的棋子卡位了,那么就交还一下移动顺序,让该子先移动,然后再移动另一个 
3。如果被上述两种情况卡位了,这种情况是不存在的,因为N皇后的性质,不在同行同列同斜线,假设存在了,那交换一下移动位置就可以了,步数还是不会变的

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 1e9
using namespace std;

int x[10],y[10],p[10];
int M[100][10];
int dp[10][1<<8];
int cnt;
void DFS(int c)//处理出8皇后的92种情况
{
    if(c == 8)
    {
        for(int i=0;i<8;i++)
            M[cnt][i] = p[i];
        cnt++;
        return;
    }
    for(int i=0;i<8;i++)
    {
        p[c] = i;
        int flag = 1;
        for(int j=0;j<c;j++)
        {
            if(p[c] == p[j] || p[c]+c == p[j]+j || p[j] - j == p[c] - c)
            {
                flag = 0;
                break;
            }
        }
        if(flag)
            DFS(c+1);
    }
}
int dis(int cur, int num, int i)
{
    int t1 = abs(x[i] - num);
    int t2 = abs(y[i] - M[cur][num]);
    int step = 0;
    if (min(t1, t2))
        step++;
    if (abs(t1 - t2))
        step++;
    return step;
}
int dfs(int cur,int num,int s)
{
    if(num == 0)
        return 0;
    if(dp[num][s] != -1)
        return dp[num][s];
    int ans = inf;
    for (int i = 0; i < 8; i++)
        if (s & (1 << i))
            ans = min(ans, dis(cur, num - 1, i) + dfs(cur, num - 1, s ^ (1 << i)));
    return dp[num][s] = ans;
}
int main(void)
{
    int T,i,j;
    char a[10][10];
    scanf("%d",&T);
    int cas = 1;
    cnt = 0;
    DFS(0);
    while(T--)
    {
        int c = 0;
        for(i=0;i<8;i++)
        {
            scanf("%s",a[i]);
            for(j=0;j<8;j++)
                if(a[i][j] == 'q')
                    x[c] = i,y[c++] = j;
        }
        int ans = inf;
        for(i=0;i<92;i++)
        {
            memset(dp,-1,sizeof(dp));
            ans = min(ans,dfs(i,8,255));
        }
        printf("Case %d: %d\n",cas++,ans);
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值