• 一双木棋 chess


    题意

    link

    \(n \times m, (n, m\leq 10)\) 的矩阵,每次可以在左上都有棋子的地方下,奇数次下在 \((i, j)\) 的价值是 \(a_{i, j}\),偶数次是 \(-b_{i, j}\)

    奇数次时想让价值和最大,偶数次时想让价值和最小。

    问最终结果。

    轮廓线dp,状压dp

    状态

    如果第 \(i\) 行放了 \(c_i\) 个,那么它一定左到右连续的。

    并且从第 \(1\) 行到第 \(n\) 行,\(c_i\) 是递减的。

    状态就可以用轮廓线唯一表示。

    \(0\) 表示 \(m\) 条横向的线,用 \(1\) 表示 \(n\) 条竖向的线。

    \(f[S]\) 表示棋盘状态 \(S\) 到全部下完的价值。

    初始和最终状态

    由于转移是从最终倒回来的。

    初始状态 \(f[111\cdots 0000\cdots] = 0\), 表示全部下完离全部下完的价值和是 0。

    其它全部设为无穷大或无穷小。

    最终状态 \(f[0000\cdots 111\cdots]\) 表示初始状态离全部下完的价值。

    转移

    能发现选一格,实际上的轮廓线就是把 \(1\) 和 下一位的 \(0\) 交换。

    选的位置可以用轮廓线状态算出来,设为 \((x, y)\)

    所以就有:
    1.偶数次时

    \[f[S] = \max_{S_i = 1, S_{i + 1} = 0} \{f[S \oplus (3 << i)] + a[x][y] \} \]

    2.奇数次时

    \[f[S] = \min_{S_i = 1, S_{i + 1} = 0} \{f[S \oplus (3 << i)] - b[x][y] \} \]

    分析

    状态是 \(O(2^{n + m})\) 的,转移是 \(O(n + m)\)

    最终是 \(O(2^{n + m}(n + m))\)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    using ll = long long;
    const int MAXN = 15;
    const int INF = 0x3f3f3f3f;
    //const int mod = 1000000007;
    int mod; 
    const double eps = 1e-9; 
    
    template <typename T>
    void Read(T &x) {
    	x = 0; T f = 1; char a = getchar();
    	for(; a < '0' || '9' < a; a = getchar()) if (a == '-') f = -f;
    	for(; '0' <= a && a <= '9'; a = getchar()) x = (x * 10) + (a ^ 48);
    	x *= f;
    }
    
    inline int add(const int &a, const int &b) { 
    	static int c;
    	c = a + b;
    	if (c >= mod) c -= mod;
    	if (c < 0) c += mod;
    	return c;   
    } 
    inline int mul(const int &a, const int &b) {
    	return 1ll * a * b % mod; 
    }
    int qpow(int a, int b) {
    	int sum(1);
    	while(b) {
    		if (b & 1) sum = mul(sum, a);
    		a = mul(a, a);
    		b >>= 1;
    	}
    	return sum; 
    }
    
    int n, m;
    int a[MAXN][MAXN], b[MAXN][MAXN];
    
    int f[1 << 21]; 
    bool vis[1 << 21];
    int dfs(int S, int N) {
    	if (vis[S]) return f[S];
    	vis[S] = 1;
    	f[S] = N ? - INF : INF;
    	int x = n, y = 0;
    	for (int i = 0; i < n + m - 1; i ++) {
    		if (S >> i & 1) x --;
    		else y ++; 
    		if ((S >> i & 3) != 1) continue;
    		int to = S ^ (3 << i);
    		if (N) f[S] = max(f[S], dfs(to, N ^ 1) + a[x + 1][y + 1]);
    		else f[S] = min(f[S], dfs(to, N ^ 1) - b[x + 1][y + 1]); 
    	}
    	return f[S];
    }
    
    int main() {
    	cin >> n >> m;
    	for (int i = 1; i <= n; i ++)
    		for (int j = 1; j <= m; j ++)
    			cin >> a[i][j];
    	for (int i = 1; i <= n; i ++)
    		for (int j = 1; j <= m; j ++)
    			cin >> b[i][j];
    	memset(f, 0x3f, sizeof(f)); 
    	f[((1 << n) - 1) << m] = 0; 
    	vis[((1 << n) - 1) << m] = 1; 
    	cout << dfs((1 << n) - 1, 1);
    	return 0;
    } 
    
  • 相关阅读:
    java 开发webservice
    myeclipse下jsp页面汉字不能保存问题
    java web项目的部署
    Java小白手记:WEB项目等
    操作系统学习笔记:虚拟内存
    面向接口编程
    WEB端应该使用DataTable/DataSet吗?
    ExtJs grid合并单元格
    操作系统学习笔记:内存管理
    Oracle中长度为0字符串与null等价
  • 原文地址:https://www.cnblogs.com/qjbqjb/p/15948504.html
Copyright © 2020-2023  润新知