1017 [SCOI2005]互不侵犯KING 状压DP板子
链接:https://ac.nowcoder.com/acm/contest/25022/1017
来源:牛客网
题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。
国王能攻击到它上下左右,以及左上 左下右上右下八个方向上附近的各一个格子,共8个格子。
输入描述:
只有一行,包含两个数N,K ( 1 ≤ N ≤ 9, 0 ≤ K ≤ N * N)
输出描述:
方案数。
分析
dp[i][j][a] 表示当前是i层,总共放了j个子,第i层状态是 k
状态转移:num[x] 是x状态有多少个棋子,b是上一层状态。
dp[i][j][a] += dp[i-1][j-num[a]][b]
当a >> 1 & b || a << 1 & b || a & b || a & a<< 1 是不合法的可以continue,也可以直接预处理掉减小时空复杂度。
可以加一个n + 1 层,答案就是n + 1层,放了k个子,状态是0(没有放子)的总方案数。
ps:变量名写错了,改了好久bug,以后用多少变量写多少变量名不然容易搞混,再不济写得不一样一点。
//-------------------------代码---------------------------- //#define int ll const int N = 9; int n,m,k; ll dp[11][90][1<<N]; int num[1<<N]; int nums[1<<N]; int st[11]; int cal(int x) { int num = 0; while(x) { if(x % 10 == 1) num ++ ; x /= 10; } return num; } void solve() { cin>>n>>k; int cnt = 0; fo(i,0,(1<<n)-1) { if(i << 1 & i) continue; st[++cnt] = i; bitset<64> bt(i); nums[cnt] = bt.count(); } fo(i,1,cnt) { // db(nums[i]); } dp[0][0][1] = 1; fo(i,1,n+1) { fo(j,0,k) { fo(p,1,cnt) { if(nums[p]>j)continue; fo(q,1,cnt) { if(st[q] << 1 & st[p] || st[q] >> 1 & st[p] || st[q] & st[p])continue; dp[i][j][p] += dp[i-1][j-nums[p]][q]; // if(j-num[p] == 0) { // dbb(i,q); // } } } } } ll ans = 0; fo(p,1,cnt) { ans += dp[n][k][p]; } cout<<ans<<endl; } signed main(){ clapping();TLE; // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------