【状态压缩dp】【轮廓线dp】【互不侵犯King】【HYSBZ】【BZOJ】【1087】

来源:互联网 发布:网络用户管理系统注册 编辑:程序博客网 时间:2024/06/06 02:29

这里是22平方傻君 , 长久没有更过博客了嘞,那么今天就来谈谈一道有趣的状态压缩题(孙便让各位进入轮廓线的深坑之中,轮廓线赛高,miku sama赛高)


这里写图片描述


problem:

 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

  方案数。

Sample Input

3 2

Sample Output

16


解法一:轮廓线dp:

这里写图片描述
首先声明,轮廓线是一种特殊的状态压缩模型。。。这东西开始学起来的时候是需要毁一下我们对状态压缩的三官,但是学会后其实会发现它是一个挺巧妙的dp思想;
轮廓线dp一般适用于方格中的操作,比如说放插头填充方块(插头dp问题),互补干扰放置问题(乱取的名字),这道题其实就是后者,各个国王的放置需要满足一定的放置条件;这一类问题几乎都是可以用另外的装压dp来解决,但是这些装压dp的思路有的会十分巧妙难想(就好比一些几何题目的巧解),而用轮廓线解题则是有规律的而且好想的(可以想成是解几何题是用的建坐标系爆算),而且只要把所有情况考虑周全便会变的佷简单;
若是没有学过轮廓线或是对它还不太熟悉的话,建议可以看看刘汝佳大大的蓝书中的对应章节;在学习之前我建议可以把轮廓线理解为是一个会滑动的状态。。。就像一条蛇一样。。。就像这样:
这里写图片描述
蛇身上的每个格子就是一个状态,然后它就开始沿着整个区域开始s型滑动;

那么这道题也是如此:

一下便是我的代码:

#include<cstdio>#include<cctype>#include<cstring>#include<iostream>#include<algorithm>#define M 100000using namespace std;int dp[2][81][1<<11] , n , m , cur ;long long ans(0);int main(){    scanf("%d %d",&n,&m);    int all = (1<<n+1) - 1;    for(int i = 1 ; i <= n*n ; cur^=1, i++){        memset(dp[cur] , 0 , sizeof dp[cur]);        dp[cur^1][0][0] = 1;        for(int k = 1 ; k <= m ; k++){            for(int j = 0 ; j <= all ; j++){                dp[cur][k][j>>1] += dp[cur^1][k][j];                if(i%n == 1 && (j&6) == 0 )dp[cur][k][(j>>1) | (1<<n)]+=dp[cur^1][k-1][j];                else if(i%n == 0 && (j&3) == 0 && (j&(1<<n)) == 0)dp[cur][k][(j>>1) | (1<<n)]+=dp[cur^1][k-1][j];                else if((j&7) == 0 && (j&(1<<n)) == 0)dp[cur][k][(j>>1) | (1<<n)]+=dp[cur^1][k-1][j];            }        }    }    for(int i = 0 ; i <= all ; i++)ans+=dp[cur^1][m][i];    printf("%lld",ans);}  

解法二:状态压缩dp

这里写图片描述
然而这道题目。。。那个N <= 9 的条件已经很明显的说明了这道题是状压了嘛 , 而且还是一道相对比较裸的题目,裸题啊。。。然后。。。我就开心的去写轮廓线去了(虽然说轮廓线其实也是一种状压)。。。考试后看了一下黄学长的博文 , 结果发现确实状态压缩的思路还是佷巧妙的。。。
链接:http://hzwer.com/1461.html

阅读全文
1 0
原创粉丝点击