zoukankan      html  css  js  c++  java
  • BZOJ1087 [SCOI2005]互不侵犯King 状压DP

    1087: [SCOI2005]互不侵犯King

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

     格子只有9*9,第一反应是dfs,写了一发TLE了

    /**************************************************************
        Problem: 1087
        User: mizersy
        Language: C++
        Result: Time_Limit_Exceed
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
    int n,k;
    int vis[15][15];
    int ans;
    bool judge(int x,int y){
        return (x >= 1 && x <= n && y >= 1 && y <= n);
    }
     
    int dx[8] = {0,0,1,1,1,-1,-1,-1};
    int dy[8] = {1,-1,1,0,-1,1,0,-1};
     
    void dfs(int x,int y,int num){
        if (num == k){
            ans++;
            return;
        }
        for (int i = (x-1)*n+y+1;i <= n*n;++i){
            int u = (i%n) ? i/n+1 : i/n,v = (i%n) ? i%n : n;
            if (judge(u,v) && !vis[u][v]){
                vis[u][v]++;
                for (int k = 0;k < 8;++k) {
                    if (judge(u+dx[k],v+dy[k])) vis[u+dx[k]][v+dy[k]]++;
                }
                dfs(u,v,num+1);
                vis[u][v]--;
                for (int k = 0;k < 8;++k)
                    if (judge(u+dx[k],v+dy[k])) vis[u+dx[k]][v+dy[k]]--;
            }
        }
    }
     
    int main(){
        ans = 0;
        scanf("%d%d",&n,&k);
        memset(vis,0,sizeof(vis));
        for (int i = 1;i <= n;++i){
            for (int j = 1;j <= n;j++)
            {
                vis[i][j]++;
                for (int k = 0;k < 8;++k)
                    if (judge(i+dx[k],j+dy[k])) vis[i+dx[k]][j+dy[k]]++;
                dfs(i,j,1);
                vis[i][j]--;
                for (int k = 0;k < 8;++k)
                    if (judge(i+dx[k],j+dy[k])) vis[i+dx[k]][j+dy[k]]--;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    DFS

    查了题解才明白是状压DP,dp[i][j][k]表示第i行状态为k,前i行国王数为j的方案数,状态转移方程为dp[i][j][k] += dp[i-1][j-num[k]][s]

    通过二进制位运算判断两种状态间以及同种状态内是否有相邻国王

    #include <bits/stdc++.h>
    using namespace std;
    long long dp[10][1000][1000];
    int all,n,m;
    int num[1000];
    int main(){
        scanf("%d%d",&n,&m);
        all = (1 << n) - 1;
        for (int i = 0;i <= all;++i){
            if ((i & (i << 1)) ||(i&(i>>1)) ) continue;
            for (int k = 1;k <= i;k <<= 1){
                if (k&i) num[i]++;
            }
            dp[1][num[i]][i] = 1;
        }
        for (int i = 2;i <= n;++i){
            for (int j = 0;j <= all;++j){
                if ((j & (j<<1)) || (j&(j>>1))) continue;
                for (int k = 0;k <= all;++k){
                    if (k&(k<<1)||(k&(k>>1))) continue;
                    if ((k&j) || (k&(j<<1)) || (k&(j>>1))) continue;
                    for (int coun = num[j] + num[k]; coun <= m;coun++){
                        dp[i][coun][k] += dp[i-1][coun-num[k]][j];
                    }
                }
            }
        }
        long long ans = 0;
        for (int i = 0;i < all;++i) ans += dp[n][m][i];
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    html 上传图片前预览
    php获取当月天数及当月第一天及最后一天、上月第一天及最后一天实现方法
    php 计算 pdf文件页数
    php 获取半年内每个月的订单数量, 总价, 月份
    php 获取两个数组之间不同的值
    小程序支付功能
    关于nginx的Job for nginx.service failed because the control process exited with error code.错误
    linux 安装 Apollo
    MongoDB待续。。。
    ABP vNext...待续
  • 原文地址:https://www.cnblogs.com/mizersy/p/9549190.html
Copyright © 2011-2022 走看看