zoukankan      html  css  js  c++  java
  • BZOJ 1087

    Magic Door

    题目大意:

    有一个n*n的棋盘,棋子可以攻击周围8个地方,求在棋盘中放入k个棋子且不会互相攻击的方案数有多少种。

    题目分析

    状态压缩: 首先将初始化每一行可能的情况(无用状态太多)存入State[].
    dp[i][k][S]表示考虑到第i行,用了k个棋子,第i行状态为S的方案数。

    [dp[i][k][S] += dp[i - 1][k - cnt(S)][valid S'] ]

    cnt(x)表示x二进制下1的个数。

    1个数的求法:原理是不断删除末尾的1并计数。

    inline int count(int x){
    	int ret;
    	for(ret = 0; x; ret++) x &= (x - 1);
    	return ret;
    }
    

    code

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 15, S = 1500;
    int n, k;
    int state[S], scnt, cnt[S];
    typedef long long ll;
    ll dp[N][N * N][S], ans;
    
    inline int count(int x){
    	int ret;
    	for(ret = 0; x; ret++) x &= (x - 1);
    	return ret;
    }
    
    inline ll DP(int x, int p, int st){
    	if(x == 0) return p == 0 ? dp[x][p][st] = 1 : dp[x][p][st] = 0;
    	if(dp[x][p][st] != -1) return dp[x][p][st];
    	ll t = 0;
    	for(int i = 1; i <= scnt; i++){
    		if(cnt[i] > p - cnt[st] || (state[i] & state[st]) || ((state[i] << 1) & state[st]) || ((state[i] >> 1) & state[st])) continue;
    		t += DP(x - 1, p - cnt[st], i);
    	}
    	return dp[x][p][st] = t;
    }
    
    int main(){
    	ios::sync_with_stdio(false);
    	cin.tie(NULL), cout.tie(NULL);
    	cin >> n >> k;
    	for(int s = 0; s < (1 << n); s++){
    		int c = count(s);
    		if((s & (s << 1)) || c > k) continue;
    		state[++scnt] = s, cnt[scnt] = c;
    //		int l = s;
    //		while(l) cout<<l % 2, l /= 2; cout<<endl;
    	}
    	memset(dp, -1, sizeof dp);
    	for(int i = 1; i <= scnt; i++)
    		ans += DP(n, k, i);
    	cout << ans << endl;
    }
    
  • 相关阅读:
    Git 安装使用及基础命令
    Ubuntu Anaconda3 环境下安装caffe
    Anaconda 安装及Python 多版本间切换
    基于 ZooKeeper 的分布式锁实现
    java 判断点是否在一条线段上
    python 安装opencv及问题解决
    python Opencv图像基础操作
    sctf pwn200
    BCTF warmup 50
    linux shadow破解
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7636290.html
Copyright © 2011-2022 走看看