@topcoder - SRM611D1L3@ ElephantDrinking
@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的更多相关文章
- TopCoder kawigiEdit插件配置
kawigiEdit插件可以提高 TopCoder编译,提交效率,可以管理保存每次SRM的代码. kawigiEdit下载地址:http://code.google.com/p/kawigiedit/ ...
- 记第一次TopCoder, 练习SRM 583 div2 250
今天第一次做topcoder,没有比赛,所以找的最新一期的SRM练习,做了第一道题. 题目大意是说 给一个数字字符串,任意交换两位,使数字变为最小,不能有前导0. 看到题目以后,先想到的找规律,发现要 ...
- TopCoder比赛总结表
TopCoder 250 500 ...
- Topcoder几例C++字符串应用
本文写于9月初,是利用Topcoder准备应聘时的机试环节临时补习的C++的一部分内容.签约之后,没有再进行练习,此文暂告一段落. 换句话说,就是本文太监了,一直做草稿看着别扭,删掉又觉得可惜,索性发 ...
- TopCoder
在TopCoder下载好luncher,网址:https://www.topcoder.com/community/competitive%20programming/ 选择launch web ar ...
- TopCoder SRM 596 DIV 1 250
body { font-family: Monospaced; font-size: 12pt } pre { font-family: Monospaced; font-size: 12pt } P ...
- 求拓扑排序的数量,例题 topcoder srm 654 div2 500
周赛时遇到的一道比较有意思的题目: Problem Statement There are N rooms in Maki's new house. The rooms are number ...
- TopCoder SRM 590
第一次做TC,不太习惯,各种调试,只做了一题...... Problem Statement Fox Ciel is going to play Gomoku with her friend ...
- Topcoder Arena插件配置和训练指南
一. Arena插件配置 1. 下载Arena 指针:http://community.topcoder.com/tc?module=MyHome 左边Competitions->Algorit ...
随机推荐
- Python之路,Day4 - Python基础(转载Alex)
本节大纲 迭代器&生成器 装饰器 基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...
- vue项目及插件
vue项目的创建 方法1: cmd中执行 vue ui vue会创建一个socket,方便快捷 方法2: 命令行建立 vue create v-proj //创建项目名为v-proj的项目文件 > ...
- JAVA Sftp 上传下载
SftpUtils package xxx;import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelSftp; import com ...
- day38 04-Spring加载配置文件
Spring的工厂类ApplicationContext有两个子类:ClassPathXmlApplicationConext和FileSystemXmlApplication都可以用来加载配置文件. ...
- 【洛谷】P1888 三角函数
P1888 三角函数 题目描述 输入一组勾股数a,b,c(a≠b≠c),用分数格式输出其较小锐角的正弦值.(要求约分.) 输入输出格式 输入格式: 一行,包含三个数,即勾股数a,b,c(无大小顺序). ...
- 洛谷P2723 丑数 Humble Numbers [2017年 6月计划 数论07]
P2723 丑数 Humble Numbers 题目背景 对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S.这个正整数集合包括, ...
- QT_强杀进程
#ifdef WIN32 bool res = false; HANDLE hToolHelp32Snapshot; hToolHelp32Snapshot = CreateToolhelp32Sna ...
- LintCode_181 将整数A转换为B
题目 如果要将整数A转换为B,需要改变多少个bit位? 如把31转换为14,需要改变2个bit位. ()10=()2 ()10=()2 思路 要考虑负数的问题 如果 一正一负 将他们去全部变成正数 后 ...
- awk notes
字符串拼接 cat sql | awk '{print " ALTER TABLE tableA ALTER " $1 " TYPE " $2 " ...
- PrintStream 类
5.PrintStream类(重点) (1)基本概念 java.io.PrintStream类用于打印各种数据内容. (2)常用的方法 PrintStream(OutputStream out) ...