首页 > 代码库 > BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
1087: [SCOI2005]互不侵犯King
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3336 Solved: 1936
[Submit][Status][Discuss]
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
orz popoqqq
状压DP,将每一行的方案二进制压成一维,令f[i][j][k]为第i行用去j个国王状态为k的方案数,然后状态转移如下:
f[i][j][k]=Σf[i-1][j-d[k]][l]
其中l&k=0,l>>1&k=0,l<<1&k=0,d[k]为k的二进制中1的个数
暴力转移即可
记得开long long
预处理来优化
需要判断自身状态可行,判断可行用了移位很巧妙!
//// main.cpp// bzoj1087//// Created by Candy on 2016/12/24.// Copyright © 2016年 Candy. All rights reserved.//#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int N=10,M=512;int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();} return x*f;}int n,m,s;int g[M][M],can[M],d[M];ll f[N][N*N][M];inline int digit(int x){ int re=0; while(x) re+=x&1,x>>=1; return re;}inline bool check(int x){return !(x<<1&x||x>>1&x);}inline bool check(int x,int y){ return !(x&y||x<<1&y||x>>1&y);}int main(int argc, const char * argv[]) { n=read();m=read();s=1<<n; for(int i=0;i<s;i++){ for(int j=i;j<s;j++)g[i][j]=g[j][i]=check(i,j); d[i]=digit(i); can[i]=check(i); } f[0][0][0]=1; for(int i=1;i<=n;i++){ int t=min(m,i*n/2+1); for(int j=0;j<=t;j++) for(int k=0;k<s;k++) if(can[k]&&d[k]<=j) for(int l=0;l<s;l++) if(can[l]&&g[k][l]&&d[k]+d[l]<=j) f[i][j][k]+=f[i-1][j-d[k]][l]; } ll ans=0; for(int i=0;i<s;i++) ans+=f[n][m][i]; printf("%lld\n",ans); return 0;}
BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。