zoukankan      html  css  js  c++  java
  • [九省联考2018]一双木棋chess

    [九省联考2018]一双木棋chess

    据说这题是可以暴力踩过去的。。

    还是考虑正解吧,是一种叫 轮廓线dp 的只听过没写过的东西

    不难发现,最后拿出来的棋子一定是左上角占的一块区域。发现 $ n + m leq 20 $ 我们可以状压一下这个区域右上到左下的边界。具体来说,我们存一个 $ 2^{n + m} $ 以内的数,1 表示向下 0 表示向左。

    是否需要再开一维状态维护当前是哪个人在下?没必要,当确定轮廓线的时候已经下的步数是确定的,所以可以知道是谁在下。为了方便实现采用记搜。

    #include "iostream"
    #include "algorithm"
    #include "cstring"
    #include "cstdio"
    using namespace std;
    #define MAXN 12
    int n , m;
    int A[MAXN][MAXN] , B[MAXN][MAXN];
    int dp[1 << 20];
    int work( int sta , int w ) {
        if( ~dp[sta] ) return dp[sta];
        dp[sta] = w ? -0x3f3f3f3f : 0x3f3f3f3f;
        int x = n , y = 0;
        for( int i = 0 ; i < n + m - 1 ; ++ i ) {
            if( sta & ( 1 << i ) ) -- x;
            else ++ y;
            if( ( ( sta >> i ) & 3 ) != 1 ) continue; // LefT,DowN
            // LefT DowN -> DowN LefT
            if( w ) dp[sta] = max( dp[sta] , work( sta ^ ( 3 << i ) , w ^ 1 ) + A[x + 1][y + 1] );
            else dp[sta] = min( dp[sta] , work( sta ^ ( 3 << i ) , w ^ 1 ) - B[x + 1][y + 1] );
        }
        return dp[sta];
    }
    int main() {
        cin >> n >> m;
        for( int i = 1 ; i <= n ; ++ i ) for( int j = 1 ; j <= m ; ++ j ) scanf("%d",&A[i][j]);
        for( int i = 1 ; i <= n ; ++ i ) for( int j = 1 ; j <= m ; ++ j ) scanf("%d",&B[i][j]);
        memset( dp , -1 , sizeof dp );
        dp[( 1 << n ) - 1 << m] = 0;
        cout << work( ( 1 << n ) - 1 , 1 ) << endl;
    }
    
  • 相关阅读:
    JavaScript创建块级作用域
    JavaScript数组求最大值 面试题
    JavaScript类数组转换为数组 面试题
    JavaScript实现深拷贝(深复制) 面试题
    javascript洗牌算法 乱序算法 面试题
    3GPP 测试 /etc/udev/ruse.d/50文件 /lib/udev/ruse.d/55* 网络配置
    【网络】TCP/IP连接三次握手
    SVN 使用方法
    Git 使用方法
    LoadRunner性能测试工具
  • 原文地址:https://www.cnblogs.com/yijan/p/12322530.html
Copyright © 2011-2022 走看看