bzoj1087互不侵犯King(状压)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1087

简单的状压dp。但是wa了好几发。注意long long。

注意0和0的连边。而且不能连成两条,所以放在外面写。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=15,M=1<<9;
int n,m,lm,list[M+5][M+5],cnt[M+5],zt[M+5],xnt,nm[M+5];//那一维是N*N!
long long ans,dp[N][N*N][M+5];//
int num(int s)
{
    int cnt=0;
    while(s)cnt++,s-=(s&-s);
    return cnt;
}
void init()
{
    lm=(1<<n);
    for(int s=0;s<lm;s++)
        if(((s<<1)&s)==0)
        {
            zt[++xnt]=s;
            nm[xnt]=num(s);
        }
    list[1][++cnt[1]]=1;
    for(int i=1;i<=xnt;i++)
        for(int j=i+1;j<=xnt;j++)
            if(((zt[i]<<1)&zt[j])==0&&((zt[i]>>1)&zt[j])==0&&(zt[i]&zt[j])==0)
                list[i][++cnt[i]]=j,list[j][++cnt[j]]=i;
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=xnt;i++)dp[1][nm[i]][i]=1;
    for(int i=2;i<=n;i++)
        for(int s=1;s<=xnt;s++)
            for(int j=nm[s];j<=m;j++)
                for(int k=1;k<=cnt[s];k++)
                    dp[i][j][s]+=dp[i-1][j-nm[s]][list[s][k]];
//                        printf("dp[%d][%d][%d]=%d(dp[%d][%d][%d]=%d) %d %d\n",i,j,s,dp[i][j][s],
//                                i-1,j-nm[s],list[s][k],dp[i-1][j-nm[s]][list[s][k]],zt[s],zt[list[s][k]]);
    for(int i=1;i<=xnt;i++)ans+=dp[n][m][i];
    printf("%lld",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/9142675.html

时间: 2024-11-08 10:28:47

bzoj1087互不侵犯King(状压)的相关文章

bzoj1087 互不侵犯King 状压dp+bitset

题目传送门 题目大意:中文题面. 思路:又是格子,n又只有9,所以肯定是状压dp,很明显上面一行的摆放位置会影响下一行,所以先预处理出怎样的二进制摆放法可以放在上下相邻的两行,这里推荐使用bitset,否则会比较麻烦.然后dp的数组是f[ i ][ x ][ j ],表示第i行已经放置了x个国王,第 i 行的状态是 j .同时预处理出对于每一种二进制位,可以增加几个国王,计做cnt[ j ],所以得到 if(mp[ s ][ j ]) f[ i +1 ][x +cnt[ j ]][ j ]+=f

BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )

简单的状压dp... dp( x , h , s ) 表示当前第 x 行 , 用了 h 个 king , 当前行的状态为 s . 考虑转移 : dp( x , h , s ) = ∑ dp( x - 1 , h - cnt_1( s ) , s' ) ( s and s' 两行不冲突 , cnt_1( s ) 表示 s 状态用了多少个 king ) 我有各种预处理所以 code 的方程和这有点不一样 ------------------------------------------------

[BZOJ1087] [SCOI2005] 互不侵犯King (状压dp)

Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Output 方案数. Sample Input 3 2 Sample Output 16 HINT Source Solution 状压$dp$就是把状态压缩成二进制数,利用二进制的位运算改进算法的一种方法

【BZOJ1087】 [SCOI2005]互不侵犯King 状压DP

经典状压DP. f[i][j][k]=sum(f[i-1][j-cnt[k]][k]); cnt[i]放置情况为i时的国王数量 前I行放置情况为k时国王数量为J 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 #define N 1<<9 5 long long ans; 6 int n,m; 7 int ok_1[N],cnt[N]; 8 int ok_2[N][N]; 9 long

BZOJ 1087 SCOI 2005 互不侵犯King 状压DP

题目大意:一个国王可以攻击到旁边8个位置的格子,现在给出一个N*N的方格,向其中放k个国王,问有多少中摆放方法. 思路:状压DP,f[i][j][k],其中i是行数,j是状态,k是已经取了多少国王.然后暴力枚举状态,看相邻两行之间有没有冲突,若没有冲突,那么就转移. 注意要开long long CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>

【题解】[SCOI2005] 互不侵犯 (状压DP)

[SCOI2005] 互不侵犯 终于懂一点状压DP了… 用一个数的二进制形式表示一整行的状态,比如 18(1010)表示第一列和第三列有国王. 然后用&判断是否可行: if((x&y)||((x<<1)&y)||(x&(y<<1))) continue;1code: #include<iostream>#include<cstdio>#include<cstring>#include<algorithm>

[SCOI2005]互不侵犯(状压Dp)

题目 原题 Solution 看到数据范围就可以想到状压,然后你就可以直接转移就好了? #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> #include<queue> #include<algorithm> #define ll long long #define file(a) freo

BZOJ1087:[SCOI2005]互不侵犯King(状压DP)

[SCOI2005]互不侵犯King Description 在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】【bzoj 1087】【SCOI 2005】互不侵犯King

1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MB Submit: 1991 Solved: 1185 Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Output 方案数. Sa