码迷,mamicode.com
首页 > 其他好文 > 详细

【题解】互不侵犯

时间:2019-08-23 19:02:29      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:main   八皇后   例子   mat   www   def   sign   cstring   初步   

仅仅是笔者对于状态压缩类\(dp\)的初步练习吧。

[题目链接](https://www.luogu.org/problem/P1896]

题目大意:给定一个\(n*n\)的棋盘,在棋盘上放国王,国王的攻击范围是它周围的八个格子。求放\(k\)个国王的合法方案数。

本题很像八皇后问题,但是由于搜索状态数量太多导致搜索会超时。我们考虑一下\(dp\)

先考虑状态设计:里面首先要包含当前使用的国王数,还可以包含某一行的信息。那么,问题来了,我们怎样判断当前状态是否合法呢?

下面就是今天的重点:状态压缩。

先给一个例子:十进制下的\(10\)转为二进制是\(1010\),我们可以用它表示:

当前行的第一个格子没有国王,第二个有,第三个没有,第四个有。

那么我们表示状态就变得容易了:用一个十进制数转成二进制数,根据它的某一位来记录状态即可。

那么我们的状态可以表示为:设\(dp[i][j][k]\)为:第\(i\)行,状态为\(j\),前\(i\)行一共放了\(k\)个国王的状态数。

那么我们如何在转移的过程中判状态呢?

考虑到有八个格子不好判断,我们可以先把状态预处理出来。显然,一个格子放了\(King\),那它的左边和右边都不能放了。

这个可以一个\(dfs\)做出来。

那么我们可以枚举了。先把第一行处理一下,因为不论如何对于任何一种状态它都有一种情况。

注意我们的\(dp\)是从上往下推的。做到无后效性。

那么对于之后的每一行,显然都有我们之前处理出来的那么多状态。我们枚举一下。

继续考虑怎么判断上下行是否合法。

若当前行的状态为\(sat[i]\),枚举到的一个状态为\(sat[j]\),则:

若$ sat[i]&sat[j] $,则它们上下有并列的\(1\),就是不合法。

若$ (sat[i]<<1)&sat[j] $,则它们左上和右下有\(1\),就是不合法。

若$ sat[i]&(sat[j]<<1) $,则它们左下和右上有\(1\),就是不合法。

去除掉这些状态之后,我们可以\(dp\)了:

因为我们求的是放国王数\(k\)个的方案数,我们可以枚举一下当前行对应的状态所对应的国王数,从\(k\)枚举到\(k-num[i]\),把符合此情况的上一行方案数累加即可。

最后统计答案,注意开\(long\) \(long\).

\(Code:\)

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define int long long
int n,k,cnt,f[10][2000][100];
int sat[2000],sats[2000];
long long Ans;
void dfs(int satet,int num,int pos){
    if(pos>=n){
        sat[++cnt]=satet;
        sats[cnt]=num;
        return;
    }
    dfs(satet,num,pos+1);
    dfs(satet+(1<<pos),num+1,pos+2);
}
signed main(){
    scanf("%lld%lld",&n,&k);
    dfs(0,0,0);
    for(int i=1;i<=cnt;++i)f[1][i][sats[i]]=1;
    for(int i=2;i<=n;++i)
        for(int j=1;j<=cnt;++j)
            for(int K=1;K<=cnt;++K){
                if(sat[j]&sat[K])continue;
                if((sat[j]<<1)&sat[K])continue;
                if(sat[j]&(sat[K]<<1))continue;
                for(int l=k;l>=sats[j];--l)f[i][j][l]+=f[i-1][K][l-sats[j]];
            }
    for(int i=1;i<=cnt;++i)Ans+=f[n][i][k];
    printf("%lld\n",Ans); 
    return 0;
}

【题解】互不侵犯

标签:main   八皇后   例子   mat   www   def   sign   cstring   初步   

原文地址:https://www.cnblogs.com/h-lka/p/11401968.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!