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;
}

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

时间: 2024-10-31 18:14:35

lightoj1061 (N Queen Again)搜索+状压dp的相关文章

URAL 1152. False Mirrors (记忆化搜索 状压DP)

题目链接 题意 : 每一颗子弹破坏了三个邻近的阳台.(第N个阳台是与第1个相邻)射击后后的生存的怪物都对主角造成伤害- 如此,直到所有的怪物被消灭,求怎样射击才能受到最少伤害. 思路 : 状压,数据不是很大,可以爆一爆,或者DFS下去就行,枚举每一种状态. 1 //1152 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #define oo 1 << 28 6 using n

UVA - 10817 Headmaster&#39;s Headache (状压dp+记忆化搜索)

题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所能教的所有科目. 2.已聘老师必须选,候选老师可选可不选. 3.dfs(cur, subject1, subject2)---求出在当前已选cur个老师,有一个老师教的科目状态为 subject1,有两个及以上老师教的科目状态为 subject2的情况下,最少的雇佣费用. dp[cur][subje

UVa 10817 (状压DP + 记忆化搜索) Headmaster&#39;s Headache

题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少. 分析: 因为s很小,所以可以用状态压缩. dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2. 在递归的过程中,还有个参数s0,表示还没有人教的科目的集合. 其中m0, m1, s0, s1, s2的计算用到位运算,还

[JZOJ5398]:Adore(状压DP+记忆化搜索)

题目描述 小$w$偶然间见到了一个$DAG$. 这个$DAG$有$m$层,第一层只有一个源点,最后一层只有一个汇点,剩下的每一层都有$k$个节点. 现在小$w$每次可以取反第$i(1<i<n-1)$层和第$i+1$层之间的连边.也就是把原本从$(i,k_1)$连到$(i+1,k_2)$的边,变成从$(i,k_2)$连到$(i+1,k_1)$. 请问他有多少种取反的方案,把从源点到汇点的路径数变成偶数条? 答案对$998244353$取模. 输入格式 一行两个整数$m,k$. 接下来$m-1$行

ZOJ3305Get Sauce 状压DP,

状压DP的题目留个纪念,首先题意一开始读错了,搞了好久,然后弄好了,觉得DFS可以,最后超时,修改了很久还是超时,没办法看了一下n的范围,然后觉得状压可以,但是没有直接推出来,就记忆化搜索了一下,可是一直错,莫名奇妙,然后没办法看了一下题解,发现了下面这个比较好的方法,然后按照这个方程去推,然后敲,也是WA了好多把,写的太搓了,没人家的清楚明了,唉~也算是给自己留个纪念,状压一直做的都不太好~唉~还好理解了, 参考了  http://blog.csdn.net/nash142857/articl

UVA 10817 Headmaster&#39;s Headache 状压DP

记录两个状态S1,S2分别记录哪些课程被1个人教过或2个人教过,然后记忆化搜索 UVA - 10817 Headmaster's Headache Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Problem D: Headmaster's Headache Time limit: 2 seconds The headmaster of Spr

状压dp入门

(先处理好基本的位运算的东西) 为了更好的理解状压dp,首先介绍位运算相关的知识. 1.'&'符号,x&y,会将两个十进制数在二进制下进行与运算,然后返回其十进制下的值.例如3(11)&2(10)=2(10). 2.'|'符号,x|y,会将两个十进制数在二进制下进行或运算,然后返回其十进制下的值.例如3(11)|2(10)=3(11). 3.'^'符号,x^y,会将两个十进制数在二进制下进行异或运算,然后返回其十进制下的值.例如3(11)^2(10)=1(01). 4.'<&

HDU 3001 状压DP

有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路  成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到任意的一个城市..然后他就在城市之间游荡.要满足他要游玩所有的城市..并且.每个城市最多去两次.要求路程最短..如果他不能游完所有的城市,,那么..就输出-1  否则 输出最短距离 如果用搜索...不靠谱  然后用搜索,, 怎么压缩?? 用一个整型数 i 表示他现在的状态..显然一个城市是要用两位..00

codevs2596 售货员的难题(状压dp)

2596 售货员的难题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题目描述 Description 某乡有n个村庄(1<n<=15),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在的村,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程最短.请你帮他选择一条最短的路. 输入描述 Input D