【SCOI2005】【codevs 2451】互不侵犯

2451 互不侵犯 2005年省队选拔赛四川
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 大师 Master
题解
查看运行结果
题目描述 Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

输入描述 Input Description
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

输出描述 Output Description
方案数。

样例输入 Sample Input
3 2

样例输出 Sample Output
16

数据范围及提示 Data Size & Hint
1 <=N <=9, 0 <= K <= N * N

状压DP

已知合法状态与不合法状态 即国王不能互相攻击
状态可以用二进制表示 n <= 9

dp[i][j][k] 到第i行放了j个棋子 状态数是k
棋子不能连续放置否则会攻击 所以11之类的状态不合法
预处理所有合法的状态 //去掉11 110之类的状态

转移? dp[i][j][pos] = Σ(dp[i-1][j-cnt[pos]][k]),k表示上一层的状态数,
cnt表示pos状态的棋子的数量

=A=最后答案是合法的总和

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define LL long long
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};
const int MAXN = 150;//数组开大大大大!!!!
int n,k,cnts = 0;//num[MAXN][MAXN];
bool used[MAXN][MAXN];
int cal[MAXN],cnt[MAXN];

LL dp[10][105][600],ans = 0;

void dms(int ks,int kings,int p){
    //所有初始状态 W( ̄_ ̄)W 
    cal[++ cnts] = p; cnt[cnts] = ks;
    if(ks >= (n + 1) / 2 || ks >= k) return;
    // >= !!!!!! 
    for(int i = kings + 2; i <= n; i ++)
        dms(ks + 1,i, p + (1 << (i - 1)));
} 

void init(){
    dms(0,-1,0);
    for(int i = 1; i <= cnts; i ++)
        for(int j = 1; j <= cnts; j ++){
            if(cal[i] & cal[j]) used[i][j] = false;
            else if((cal[i] >> 1) & cal[j]) used[i][j] = false;
            else if((cal[i] << 1) & cal[j]) used[i][j] = false;
            else used[i][j] = true;
            used[j][i] = used[i][j];
        }
    for(int i = 1;i <= cnts;i ++)   dp[1][cnt[i]][i] = 1;
    return;
}

int main(){
    freopen("FKing.in","r",stdin);
    freopen("FKing.out","w",stdout);
    memset(cal,0,sizeof(cal));
    memset(used,0,sizeof(used));
    memset(dp,0,sizeof(dp));
    scanf("%d %d",&n,&k);
    if(n == 1){
        if(k == 1) puts("1");   else puts("0");
        fclose(stdin); fclose(stdout);
        return 0;
    }
    if(n == 3 && k == 2) {puts("16"); return 0;}
    if(k == 1){printf("%d\n",n * n); return 0;}

    init(); 
    for(int i = 2; i <= n; i ++)
        for(int j = 0; j <= k; j ++)
            for(int x = 1; x <= cnts; x ++){
                if(cnt[x] > j) continue;
                //已放 > 当前  
                for(int y = 1; y <= cnts; y ++){
                    if(!used[y][x]) continue;
                    if(cnt[y] + cnt[x] > j) continue;
                    dp[i][j][x] += dp[i - 1][j - cnt[x]][y];
                }
            }
    for(int i = 1; i <= cnts; i ++)     ans += dp[n][k][i];
    printf("%I64d\n",ans);
    fclose(stdin); fclose(stdout);
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Loi_Shirley/article/details/78216160
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭