zoukankan      html  css  js  c++  java
  • agc004_e Salvage Robots

    题目链接

    点击打开链接

    题解

    可以将题目看作出口在移动。如果出口最初的位置为 ((r_0,c_0)) (第 (r) 行第 (c) 列),某一时刻位置为 ((x,y)) ,那么对于一个机器人 ((p,q)) ,如果 (ple x-r_0) 或者 (pge x+H-c_0) 或者 (qle y-c_0) 或者 (q ge y+W-c_0) ,那么他已经死掉了。

    (f_{l,r,u,d}) 表示历史上出口到达过的最小行坐标为 (r_0-l) ,最大行坐标为 (r_0+r) ,最小列坐标为 (c_0-u) ,最大列坐标为 (c_0+d) 。我们可以通过 (l,r,u,d) 计算出哪些范围内的机器人没有被吃掉。

    转移直接将 (l,r,u,d) 之中的一个挪动一格。

    具体地,(f_{l,r,u,d} ightarrow f_{l+1,r,u,d}+s) ,其中 (s) 为新拯救的一行的一部分的和。

    实现的话,仁者见仁,智者见智了。

    这题有点卡空间,可以这样:

    • short 存储 dp 数组
    • 其实有用的部分只有 (r_0cdot c_0cdot (H-r_0)cdot (W-c_0)) 这么多个,很明显用均值不等式就可以推出最多 (50^4) 个有用部分。大概写个哈希就行,不过只用上一个优化就能过了。

    代码

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int NH = 105, NW = 105;
    int H, W, r0, c0;
    char mp[NH][NW];
    short dp[105][105][105][105];
    int sum[NH][NW];
    int GetSum(int r1, int c1, int r2, int c2) {
    	return sum[r2][c2] - sum[r1 - 1][c2] - sum[r2][c1 - 1] + sum[r1 - 1][c1 - 1];
    }
    int max(int x, int y) { return (x > y) ? x : y; }
    int min(int x, int y) { return (x < y) ? x : y; }
    int main() {
    	scanf("%d%d", &H, &W);
    	for (int i = 1; i <= H; ++i) scanf("%s", mp[i] + 1);
    	for (int i = 1; i <= H; ++i)
    		for (int j = 1; j <= W; ++j)
    			if (mp[i][j] == 'E') {
    				r0 = i;
    				c0 = j;
    				break ;
    			}
    	for (int i = 1; i <= H; ++i)
    		for (int j = 1; j <= W; ++j)
    			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + (mp[i][j] == 'o');
    	memset(dp, 0x8f, sizeof(dp));
    	dp[0][0][0][0] = 0;
    	int ans = 0;
    	for (int s = 0; s <= H - 1 + W - 1; ++s)
    		for (int l = 0; l <= c0 - 1; ++l)
    			for (int r = 0; r <= W - c0 && l + r <= s; ++r)
    				for (int u = 0; u <= r0 - 1 && l + r + u <= s; ++u) {
    					int d = s - l - r - u;
    					if (r0 + d > H || d < 0) continue ;
    					int lu, ld, ll, lr;
    					lu = max((r0 + d) - (r0 - 1), 1);
    					ld = min((r0 - u) + (H - r0), H);
    					ll = max((c0 + r) - (c0 - 1), 1); //这开始写错了
    					lr = min((c0 - l) + (W - c0), W);
    					int r1, c1, r2, c2;
    					r1 = r0 - u;
    					c1 = c0 - l;
    					r2 = r0 + d;
    					c2 = c0 + r;
    					if (r1-1 >= 1) {
    						int u1 = u + 1;
    						if (r1-1 >= lu) {
    							dp[l][r][u1][d] = max(dp[l][r][u1][d], dp[l][r][u][d] + GetSum(r1-1, max(ll, c1), r1-1, min(lr, c2)));
    						} else dp[l][r][u1][d] = max(dp[l][r][u1][d], dp[l][r][u][d]);
    					}
    					if (r2+1 <= H) { //这不是 else if
    						int d1 = d + 1;
    						if (r2+1 <= ld) {
    							dp[l][r][u][d1] = max(dp[l][r][u][d1], dp[l][r][u][d] + GetSum(r2+1, max(ll, c1), r2+1, min(lr, c2)));
    						} else dp[l][r][u][d1] = max(dp[l][r][u][d1], dp[l][r][u][d]);
    					}
    					if (c1-1 >= 1) {
    						int l1 = l + 1;
    						if (c1-1 >= ll) {
    							dp[l1][r][u][d] = max(dp[l1][r][u][d], dp[l][r][u][d] + GetSum(max(lu, r1), c1-1, min(ld, r2), c1-1));
    																						//这里的取 max要注意
    						} else dp[l1][r][u][d] = max(dp[l1][r][u][d], dp[l][r][u][d]);
    					}
    					if (c2+1 <= W) {
    						int rr1 = r + 1;
    						if (c2+1 <= lr) {
    							dp[l][rr1][u][d] = max(dp[l][rr1][u][d], dp[l][r][u][d] + GetSum(max(lu, r1), c2+1, min(ld, r2), c2+1));
    						} else dp[l][rr1][u][d] = max(dp[l][rr1][u][d], dp[l][r][u][d]);
    					}
    					ans = max(dp[l][r][u][d], ans);
    				}
    	printf("%d
    ", ans);
    	return 0;
    }
    
    
  • 相关阅读:
    游标加标量函数
    将一个Excel文件分隔成多个
    网页抓取的一个小例子
    ajax跨域问题
    ssh连接至Ubuntu服务器时,提示以下错误:REMOTE HOST IDENTIFICATION HAS CHANGED!
    Python 实现汉诺塔问题(递归)
    Ubuntu下环境变量设置
    文件上传 jqueryForm
    Oracle数据库安装完成后相关问题的解决
    Java中16进制与字符串之间的相互转换
  • 原文地址:https://www.cnblogs.com/YouthRhythms/p/13586271.html
Copyright © 2011-2022 走看看