zoukankan      html  css  js  c++  java
  • POJ 1321 棋盘问题(状态压缩DP | DFS)

    题意:

    在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k 个棋子的所有可行的摆放方案C。

    思路:

    1. 把每一行的摆放情况看作是一个状态,则最多有 2个状态,本题不超过 2^8;

    2. 如果用状态压缩的动态规划来看待的话有: 第 i 行不放棋子,dp[i][s] = dp[i-1][s]; 第 i 行摆放棋子,dp[i][news] = dp[i-1][s];

    3. 用滚动数组来节省内存,并且 news > s,所以要逆序求第 i 行的状态,方能得到正确的解。

    状态压缩DP:0ms

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    char grid[10][10];
    int N, K, ans, dp[2][1<<8];
    
    int main() {
        while (scanf("%d%d", &N, &K)) {
            if (N == -1 && K == -1)
                break ;
            for (int i = 0; i < N; i++)
                scanf("%s", &grid[i][0]);
    
            int t1 = 1, t2 = 0;
            memset(dp, 0, sizeof(dp));
    
            dp[0][0] = 1;
            for (int i = 0; i < N; i++) {
                t1 ^= 1, t2 ^= 1;
                for (int s = (1<<N)-1; s >=0 ; s--) {
                    dp[t2][s] = dp[t1][s];
                    for (int j = 0; j < N; j++)
                        if (grid[i][j] == '#' && !(s & (1<<j)))
                            dp[t2][s|(1<<j)] += dp[t1][s];
                }
            }
            int ans = 0;
            for (int s = 0; s < 1<<N; s++) {
                int m = 0, t = s;
                while (t > 0) {
                    t &= (t-1);
                    m += 1;
                }
                if (m == K) 
                    ans += dp[t2][s];
            }
            printf("%d\n", ans);
        } 
    }

    DFS + 剪枝:16ms

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    char grid[10][10];
    int N, K, ans;
    
    void dfs(int l, int k, int flag) {
        if (k == 0) {
            ans++;
            return ;
        }
    
        if (l > N || N - l + 1 < k)
            return ;
    
        dfs(l + 1, k, flag);
    
        for (int i = 1; i <= N; i++) {
            if (grid[l][i] == '#' && !(flag & (1<<i))) {
                dfs(l + 1, k - 1, flag | (1<<i));
            }
        }
    }
    
    int main() {
        while (scanf("%d%d", &N, &K)) {
            if (N == -1 && K == -1)
                break ;
            for (int i = 1; i <= N; i++)
                scanf("%s", &grid[i][1]);
    
            ans = 0;
            dfs(1, K, 0);
            printf("%d\n", ans);
        } 
    }
  • 相关阅读:
    大数据测试2
    大数据测试3
    CROSS APPLY和 OUTER APPLY 区别详解
    SQL中的escape的用法
    Sql Server参数化查询之where in和like实现详解
    多行文本框换行符处理
    Cross Apply的用法
    交叉连接Cross Join的用法
    统计字符串中某个字符的个数
    JOIN用法
  • 原文地址:https://www.cnblogs.com/kedebug/p/2967156.html
Copyright © 2011-2022 走看看