@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. 解决Cesium1.50对gltf2.0/3dtiles数据读取的问题

    问题说明 Cesium 1.50(2018/10/01)版本打开3dtiles可能会出现加载不上导致渲染停止的错误. 错误说明为:RuntimeError: Unsupported glTF Exte ...

  2. IO流4 --- IO流体系 --- 技术搬运工(尚硅谷)

  3. 学习JDK1.8集合源码之--ArrayDeque

    1. ArrayDeque简介 ArrayDeque是基于数组实现的一种双端队列,既可以当成普通的队列用(先进先出),也可以当成栈来用(后进先出),故ArrayDeque完全可以代替Stack,Arr ...

  4. ubuntu16.04上在使用搜狗输入法时,按shift不能正常切换中英文

    问题描述: ubuntu16.04上在使用搜狗输入法时,不知道把什么组合键给错按了,导致了按shift不能正常切换中英文,这是一件很烦恼的事儿! 解决步骤: 1,终端输入打开: fcitx-confi ...

  5. LUGOU 3959 宝藏 (noip 2017 day2 T2)

    传送门 解题思路 去年noip现在拿来写..思路还是听清楚的,记忆化搜索,f[S]表示现在选了集合S时的最小代价,dis[i]表示达到最优时i这个点的深度.f[S| (1< < i-1) ...

  6. ML面试1000题系列(81-90)

    本文总结ML面试常见的问题集 转载来源:https://blog.csdn.net/v_july_v/article/details/78121924 81.已知一组数据的协方差矩阵P,下面关于主分量 ...

  7. Ajax--解析JSON数据与解析XML数据

    一.Ajax解析JSON数据 nav.json(json数据) [ { "link":"http://www.jd.com", "src": ...

  8. CSS(前)篇

    1.1CSS重点总结 1.1.1 选择器 1.1.2 盒子模型 1.1.3 浮动 1.1.4定位 1.2CSS介绍 概念: 层叠样式表或者级联样式表(Cascading Style Sheets) 层 ...

  9. web前端学习(三)css学习笔记部分(3)-- css常用操作

    5.  CSS常用操作 5.1  对齐 使用margin属性进行水平对齐 <!DOCTYPE html> <html lang="en"> <head ...

  10. Hdu 3068 最长回文字串Manacher算法

    题目链接 最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...