zoukankan      html  css  js  c++  java
  • 【58.75%】【BZOJ 1087】[SCOI2005]互不侵犯King

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3040  Solved: 1786
    [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

    【题解】

    设f[i][j][k]表示在第i行的放国王的序列为k,然后前i行放了j个国王的方案数;

    f[i][j][k] = ∑[i-1][j-count[k]][pre_zhuangtai];

    然后就是pre_zhuangtai 要怎么和k状态配对呢?

    就是说你怎么知道这两行的国王不会发生冲突?

    可以用dfs预处理出来。

    然后用碉堡了的位运算来获取不合法的关系。剩下的就是合法的了。

    1

    1


    1

    01


    01

    10


    像上面3个都是不合法的会发现

    x<<1 x>>1 x 分别和y进行&运算。如果大于0.就是不合法的了。

    记录下某两个状态是不是合法的就可以了。

    【代码】

    #include <cstdio>
    #include <cstring>
    
    const int MAXN = 101;
    
    int n, k, n_zt = 0, zt[MAXN], count[MAXN];
    long long f[10][101][101];
    bool can[MAXN][MAXN];
    
    void dfs(int num, int pre, int zhuangtai)
    {
    	n_zt++;
    	zt[n_zt] = zhuangtai;
    	count[n_zt] = num;
    	if (num >= k)
    		return;
    	for (int i = pre + 2; i <= n; i++)
    		dfs(num + 1, i, zhuangtai + (1 << (i - 1)));
    }
    
    int main()
    {
    	//freopen("F:\rush.txt", "r", stdin);
    	memset(can, true, sizeof(can));
    	scanf("%d%d", &n, &k);
    	dfs(0, -1, 0);
    	for (int i = 1; i <= n_zt; i++)
    		for (int j = 1; j <= n_zt; j++)
    			if ((zt[i] & zt[j]) || ((zt[i] << 1) & zt[j]) || ((zt[i] >> 1) & zt[j]))
    				can[j][i] = can[i][j] = false;
    	for (int i = 1; i <= n_zt; i++)
    		f[1][count[i]][i] = 1;
    	for (int i = 2;i <= n;i++)//枚举当前是第几行。
    		for (int j = 0;j <= k;j++)//枚举当总共放了多少个国王
    			for (int now = 1; now <= n_zt; now++)//枚举当前行的状态是什么
    			{
    				if (j < count[now])//如果枚举当前行状态的国王数目大于当前枚举的则跳过。
    					continue;
    				for (int prezt = 1; prezt <= n_zt; prezt++)//枚举前一行的状态是什么
    					if (can[prezt][now] && count[prezt] + count[now] <= j)
    						f[i][j][now] += f[i - 1][j - count[now]][prezt];
    				//如果这两行符合规则.且前一行的国王的数目加上这一行的国王的数目小于等于
    				//当前枚举的车的数目;
    				//这一行贡献了count[now]个国王。则前i-1行贡献了j-count[now]个国王.
    			}
    	long long ans = 0;
    	for (int i = 1; i <= n_zt; i++)
    		ans += f[n][k][i];
    	printf("%lld
    ", ans);
    	return 0;
    }


  • 相关阅读:
    OCP-1Z0-053-V12.02-235题
    OCP-1Z0-053-V12.02-524题
    OCP-1Z0-053-V12.02-525题
    OCP-1Z0-053-V12.02-526题
    OCP-1Z0-053-V12.02-535题
    OCP-1Z0-053-V12.02-540题
    OCP-1Z0-053-V12.02-617题
    OCP-1Z0-053-V12.02-649题
    如何制作Jar包并在android中调用jar包
    JAVA实现回调
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632230.html
Copyright © 2011-2022 走看看