首页 > 代码库 > lightoj1061 (N Queen Again)搜索+状压dp

lightoj1061 (N Queen Again)搜索+状压dp

题意:(八皇后问题的变形)给定8个皇后的位置,然后问最少要走几步使得每个皇后之间可以不相互攻击(不在同一行同一列同一斜线)。其中走的过程每步可以横着竖着斜着走多个格子。


解法:先枚举所有合法的八皇后局面(总共92种)。然后将给的点对合法八皇后局面进行匹配。dp[i][j]表示合法八皇后前i个点用掉给定八皇后集合的子集j所花费的最小步数。这里的匹配相当于两个集合各八个点,进行一一配对。原来想的是ans[i][j]的i是合法皇后状态子集,但是这样会有增加好多复杂度。前边的dp[i][j]可以在8*255*8的复杂度内解决问题。如果是后者则是8*8*255*255.再加上有个92就超时了。

   ps:这里有个假设,就是如果匹配完之后,一定可以有个顺序使得每个皇后都可以顺利走到匹配的位置而不被其他皇后挡住。我的理解是这样:如果要走的一个匹配被其他某个皇后挡住了,那么会分为两种情况:1 挡道的皇后是移动之后的 解决这个就是交换他们的移动顺序。  2 挡道的皇后是移动之前 依然是交换他们的移动顺序。并且这里不会出现A移动之前挡住B,移动之后依然挡住B的情况,否则就交换他们的目标位置(不会增加步数,画图可以看出)。


代码:

/****************************************************
* author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>

using namespace std;

#define eps 1e-8
typedef long long LL;
struct point
{
    int x,y;
} points[10];
char out[10][10];
int num[10];
int dp[10][300];
char s[10][10];
int tot=0;
int ans=0;
int p=0;
void read()
{
    tot=0;
    p=0;
    char c;
    for(int i=0; i<8; i++)
        scanf("%s",s[i]);
    for(int i=0; i<8; i++)
        for(int j=0; j<8; j++)
            if(s[i][j]==‘q‘)
            {
                points[p].x=i;
                points[p++].y=j;
                //cout<<i<<" "<<j<<endl;
            }
}
int getdis(int i,int j)
{
    int t1=abs(points[j].y-num[i]);
    int t2=abs(points[j].x-i);
    int res=0;
    if(min(t1,t2))
        res++;
    if(abs(t1-t2))
        res++;
    return res;
}
int make(int i,int j)
{
    if(dp[i][j]!=-1)
        return dp[i][j];
    int tool=1000;
    for(int k=0; k<8; k++)
    {
        if(j&(1<<k))
        {
            tool=min(tool,getdis(i-1,k)+make(i-1,j-(1<<k)));
        }
    }
    return dp[i][j]=tool;
}
void solve()
{
    memset(dp,-1,sizeof dp);
    dp[0][0]=0;
    ans=min(ans,make(8,255));
}
int sum=0;
void dfs(int k)
{
    if(k==8)
    {
        sum++;
        int p=ans;
        solve();
        memset(out,‘.‘,sizeof out);
        for(int i=0; i<8; i++)
            out[num[i]][i]=‘p‘;
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<8; j++)
                ;//putchar(out[i][j]);
            //cout<<endl;
        }
        return ;
    }
    for(int j=0; j<8; j++)
    {
        num[k]=j;
        bool flag=1;
        for(int i=0; i<k; i++)
        {
            if((num[i]==num[k])||(i+num[i]==k+num[k])||(i-num[i]==k-num[k]))
            {
                flag=0;
                break;
            }
        }
        if(flag)
            dfs(k+1);
    }
}
int main()
{
    int t;
    cin>>t;
    int kk=0;
    while(t--)
    {
        kk++;
        ans=1000;
        read();
        dfs(0);
        printf("Case %d: %d\n",kk,ans);
    }
    return 0;
}