@description@

给定有一个 n*n 的平原,其中一些格子有些泉水。泉水每单位时间生产的水量有多有少。

平原周围有 4*n 头大象,如下图所示的绿色部分。大象可以将鼻子笔直伸向自己面对的方向喝泉水(假设鼻子长到可以触碰对面边缘),如下图所示红色线段。

本题还有些额外限制:大象的鼻子不能相交;每个泉水最多被一个大象占领。如图 (a) 是合法的,图 (b) 都算大象的鼻子相交。

请计算大象们每单位时间最多能喝多少的水。

Class:

ElephantDrinking

Method:

maxSum

Parameters:

String[]

Returns:

int

Constraints

n 在 2 到 50 之间。通过字符串数组来描述平原,其中字符串 i 的第 j 位为一个 '0'~'9' 的数,描述平原 (i, j) 的单位时间产水量(0 则不产水)。

Examples

0)

{"00000",

"00110",

"01000",

"00100",

"00000"}

Returns: 4

1)

{"111",

"191",

"111"}

Returns: 16

@solution@

这个 dp。。。虽然不难理解。。。但是好像有点乱搞。。。

(注:以下的图片都不是我画的,是从其他地方截下来的)

首先我们令 a 表示最左面的大象的鼻子向右最远延伸到多少行,同理定义 b 表示最右,c 表示最下,d 表示最上。

考虑如果 a <= b,实际上中间形成了一条可以供上下的大象自由伸展鼻子的区域(如下图)。

我们假设预处理出 f[i][j] 表示仅考虑左大象和上大象时,取矩阵左上部分到 (i, j) 这一区域的最优答案。同理再预处理出仅考虑左、下;仅考虑右、上;仅考虑右、下的值。

则上图中蓝、黄、青、紫区域的答案就是我们预处理出来的值。

橙色区域实际上每一列只会有两头大象,所以处理出每一列的最大值与次大值之和即可。

如果 d <= c,其实就是把上下变成了左右,一样的处理即可。

如果 a > b 且 d > c,实际上形成了像是弦图的模样(如下图):

只需要枚举中间那个空的矩形即可,一样利用我们预处理好的信息。

当然它还可以转个方向(如下图),不过处理方法还是一样:

现在考虑怎么预处理出 f[i][j] 呢?这里仅说明左、上的情况,其他情况类似。

我们枚举最后一行的大象鼻子延伸的位置;再枚举一列,使那一列上面的大象鼻子延伸至最后一行,且那一列左边没有任何大象延伸至最后一行。枚举的那一列右边的大象没有限制,故肯定延伸至最大泉水处。

这样总时间复杂度就是 O(n^4) 的,可以很轻松地跑过。

@accepted code@

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 50;
class ElephantDrinking{
public:
int a[MAXN + 5][MAXN + 5], n;
int tmp[MAXN + 5], res;
int f1[MAXN + 5][MAXN + 5];
void get_lu() {
for(int j=1;j<=n;j++) tmp[j] = 0;
memset(f1, 0, sizeof f1);
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
tmp[j] = max(tmp[j], a[i][j]);
for(int k=0;k<=j;k++) {
res = a[i][k], f1[i][j] = max(f1[i][j], res + f1[i-1][j]);
for(int l=j;l>k;l--)
res += tmp[l], f1[i][j] = max(f1[i][j], res + f1[i-1][l-1]);
}
// printf("* %d %d : %d\n", i, j, f1[i][j]);
}
}
}
int f2[MAXN + 5][MAXN + 5];
void get_ld() {
for(int j=1;j<=n;j++) tmp[j] = 0;
memset(f2, 0, sizeof f2);
for(int i=n;i>=1;i--) {
for(int j=1;j<=n;j++) {
tmp[j] = max(tmp[j], a[i][j]);
for(int k=0;k<=j;k++) {
res = a[i][k], f2[i][j] = max(f2[i][j], res + f2[i+1][j]);
for(int l=j;l>k;l--)
res += tmp[l], f2[i][j] = max(f2[i][j], res + f2[i+1][l-1]);
}
// printf(". %d %d : %d\n", i, j, f2[i][j]);
}
}
}
int f3[MAXN + 5][MAXN + 5];
void get_ru() {
for(int j=1;j<=n;j++) tmp[j] = 0;
memset(f3, 0, sizeof f3);
for(int i=1;i<=n;i++) {
for(int j=n;j>=1;j--) {
tmp[j] = max(tmp[j], a[i][j]);
for(int k=n+1;k>=j;k--) {
res = a[i][k], f3[i][j] = max(f3[i][j], res + f3[i-1][j]);
for(int l=j;l<k;l++)
res += tmp[l], f3[i][j] = max(f3[i][j], res + f3[i-1][l+1]);
}
// printf("? %d %d : %d\n", i, j, f3[i][j]);
}
}
}
int f4[MAXN + 5][MAXN + 5];
void get_rd() {
for(int j=1;j<=n;j++) tmp[j] = 0;
memset(f4, 0, sizeof f4);
for(int i=n;i>=1;i--) {
for(int j=n;j>=1;j--) {
tmp[j] = max(tmp[j], a[i][j]);
for(int k=n+1;k>=j;k--) {
res = a[i][k], f4[i][j] = max(f4[i][j], res + f4[i+1][j]);
for(int l=j;l<k;l++)
res += tmp[l], f4[i][j] = max(f4[i][j], res + f4[i+1][l+1]);
}
// printf("! %d %d : %d\n", i, j, f4[i][j]);
}
}
}
int solve1() {
int ret = 0, res1 = 0, res2 = 0, res3 = 0, mx = 0, smx = 0;
for(int i=0;i<=n;i++) {
res1 = res2 = 0;
for(int k=1;k<=n;k++)
res1 = max(res1, a[k][i] + f1[k-1][i] + f2[k+1][i]);
for(int j=i+1;j<=n+1;j++) {
res3 = 0;
for(int k=1;k<=n;k++)
res3 = max(res3, a[k][j] + f3[k-1][j] + f4[k+1][j]);
ret = max(ret, res1 + res2 + res3);
if( j == n + 1 ) break;
mx = smx = 0;
for(int k=1;k<=n;k++) {
if( a[k][j] > mx )
smx = mx, mx = a[k][j];
else if( a[k][j] > smx )
smx = a[k][j];
}
res2 += (mx + smx);
}
}
return ret;
}
int solve2() {
int ret = 0, res1 = 0, res2 = 0, res3 = 0, mx = 0, smx = 0;
for(int i=0;i<=n;i++) {
res1 = res2 = 0;
for(int k=1;k<=n;k++)
res1 = max(res1, a[i][k] + f1[i][k-1] + f3[i][k+1]);
for(int j=i+1;j<=n+1;j++) {
res3 = 0;
for(int k=1;k<=n;k++)
res3 = max(res3, a[j][k] + f2[j][k-1] + f4[j][k+1]);
ret = max(ret, res1 + res2 + res3);
if( j == n + 1 ) break;
mx = smx = 0;
for(int k=1;k<=n;k++) {
if( a[j][k] > mx )
smx = mx, mx = a[j][k];
else if( a[j][k] > smx )
smx = a[j][k];
}
res2 += (mx + smx);
}
}
return ret;
}
int solve3() {
int ret = 0;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
for(int k=1;k<n;k++)
for(int l=k+1;l<=n;l++) {
ret = max(ret, f1[i][l-1] + f2[i+1][k] + f3[j-1][l] + f4[j][k+1]);
ret = max(ret, f1[j-1][k] + f2[j][l-1] + f3[i][k+1] + f4[i+1][l]);
}
return ret;
}
int maxSum(vector<string>field) {
n = field.size();
memset(a, 0, sizeof a);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i + 1][j + 1] = field[i][j] - '0';
get_lu(), get_ld(), get_ru(), get_rd();
return max(max(solve1(), solve2()), solve3());
}
}ED;

@details@

写得来,但就是想不到。。。

写的时候 Ctrl + c 与 Ctrl + v 用得很爽 2333。

@topcoder - SRM611D1L3@ ElephantDrinking的更多相关文章

  1. TopCoder kawigiEdit插件配置

    kawigiEdit插件可以提高 TopCoder编译,提交效率,可以管理保存每次SRM的代码. kawigiEdit下载地址:http://code.google.com/p/kawigiedit/ ...

  2. 记第一次TopCoder, 练习SRM 583 div2 250

    今天第一次做topcoder,没有比赛,所以找的最新一期的SRM练习,做了第一道题. 题目大意是说 给一个数字字符串,任意交换两位,使数字变为最小,不能有前导0. 看到题目以后,先想到的找规律,发现要 ...

  3. TopCoder比赛总结表

    TopCoder                        250                              500                                 ...

  4. Topcoder几例C++字符串应用

    本文写于9月初,是利用Topcoder准备应聘时的机试环节临时补习的C++的一部分内容.签约之后,没有再进行练习,此文暂告一段落. 换句话说,就是本文太监了,一直做草稿看着别扭,删掉又觉得可惜,索性发 ...

  5. TopCoder

    在TopCoder下载好luncher,网址:https://www.topcoder.com/community/competitive%20programming/ 选择launch web ar ...

  6. TopCoder SRM 596 DIV 1 250

    body { font-family: Monospaced; font-size: 12pt } pre { font-family: Monospaced; font-size: 12pt } P ...

  7. 求拓扑排序的数量,例题 topcoder srm 654 div2 500

    周赛时遇到的一道比较有意思的题目: Problem Statement      There are N rooms in Maki's new house. The rooms are number ...

  8. TopCoder SRM 590

     第一次做TC,不太习惯,各种调试,只做了一题...... Problem Statement     Fox Ciel is going to play Gomoku with her friend ...

  9. Topcoder Arena插件配置和训练指南

    一. Arena插件配置 1. 下载Arena 指针:http://community.topcoder.com/tc?module=MyHome 左边Competitions->Algorit ...

随机推荐

  1. linux 下 nginx 的最大文件打开设置

    先设置好linux 系统的 limit, 见其他博文 nginx 也有自己的 limit 设置: 1. nginx.conf 设置  worker_rlimit_nofile 例如:  worker_ ...

  2. php 抽奖概率算法

    lottery.php <?php //转自https://segmentfault.com/a/1190000007431893 /* * 不同概率的抽奖原理就是把0到*(比重总数)的区间分块 ...

  3. Leetcode653.Two Sum IV - Input is a BST两数之和4-输入BST

    给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true. struct TreeNode { int val; struct TreeNode * ...

  4. 如何用git将项目代码上传到github - CSDN博客

    配置Git 我们先在电脑硬盘里找一块地方存放本地仓库,比如我们把本地仓库建立在C:\MyRepository\1ke_test文件夹下 进入1ke_test文件夹 鼠标右键操作如下步骤: 1)在本地仓 ...

  5. 虚拟机安装redis

    sudo pecl install redis 先代码里先phpinfo(); 看看php版本 有可能是7.2 sudo vim /etc/php/7.1/fpm/php.ini    (注意 php ...

  6. bzoj 1026 [SCOI2009]windy数——数位dp水题

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1026 迷恋上用dfs写数位dp了. #include<iostream> #in ...

  7. opencv 图像基本操作

    目录:读取图像,获取属性信息,图像ROI,图像通道的拆分和合并 1.  读取图像 像素值返回:直接使用坐标即可获得, 修改像素值:直接通过坐标进行赋值 能用矩阵操作,便用,使用numpy中的array ...

  8. git update-index --assume-unchanged忽略跟踪

    Git 忽略已跟踪文件的改动 git update-index --assume-unchanged Git之本地忽略 这个分两种情况: 本地永久忽略,效果的gitignore一样,只不过不适于写到g ...

  9. Eclipse创建jsp web项目

    Eclipse 是一个开放源代码的.基于Java的可扩展开发平台.就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境.幸运的是,Eclipse 附带了一个标准的插件集,包括Java开 ...

  10. TYVJ1340 送礼物

    P1340 送礼物 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 作为惩罚,GY被遣送去帮助某神牛给女生送礼物(GY:貌似是个好差事)但是在GY看到礼物之后 ...