title
【问题描述】
相信大家都写过数字三角形问题,题目很简单求最大化一个三角形数塔从上往下走的路径和。走的规则是:(i,j)号点只能走向(i+1,j)或者(i+1,j+1)。如下图是一个数塔,映射到该数塔上行走的规则为:从左上角的点开始,向下走或向右下走直到最底层结束。
1
3 8
2 5 0
1 4 3 8
1 4 2 5 0
路径最大和是1+8+5+4+4 = 22,1+8+5+3+5 = 22或者1+8+0+8+5 = 22。
小S觉得这个问题so easy。于是他提高了点难度,他每次ban掉一个点(即规定哪个点不能经过),然后询问你不走该点的最大路径和。
当然他上一个询问被ban掉的点过一个询问会恢复(即每次他在原图的基础上ban掉一个点,而不是永久化的修改)。
【输入】
第一行包括两个正整数,N,M,分别表示数塔的高和询问次数。
以下N行,第i行包括用空格隔开的i - 1个数,描述一个高为N的数塔。
而后M行,每行包括两个数X,Y,表示第X行第Y列的数塔上的点被小S ban掉,无法通行。
(由于读入数据较大,c或c++请使用较为快速的读入方式)
【输出】
M行每行包括一个非负整数,表示在原图的基础上ban掉一个点后的最大路径和,如果被ban掉后不存在任意一条路径,则输出-1。
【输入输出样例1】
tower. in
5 3
1
3 8
2 5 0
1 4 3 8
1 4 2 5 0
2 2
5 4
1 1
tower.out
17
22
-1
【样例解释】
第一次是
1
3 X
2 5 0
1 4 3 8
1 4 2 5 0
1+3+5+4+4 = 17 或者 1+3+5+3+5=17
第二次:
1
3 8
2 5 0
1 4 3 8
1 4 2 X 0
1+8+5+4+4 = 22
第三次:你们都懂的!无法通行,-1!扫描二维码关注公众号,回复: 6124365 查看本文章
【数据范围】
analysis
-
看到数字三角形,我笑了,毕竟 入门题目,再往下看,我的笑容逐渐凝固。。
-
但还是套上数字三角形的板子,标记了被 掉的点,在线做,样例就很容易的过了,然而时间复杂度是 ,肯定 ,那就只能想其他方法了。
-
然后我们可以发现: 我们可以 去预处理一下,
表示 到点 的最大路径和。
则表示 到 的最大路径和。
然后我们这样就可以发现:
就是从第 层到第 层经过点 的最大路径和!
然后我们每一层找一个左边点 最大的 ,
跟一个右边点 最大的。
这样查询的时间为 ,时间复杂度就变成了 。 -
看起来很简单,仔细想想后确实也不难,然而我还是想了快一个小时,还是慢慢提高吧。。
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
int a[maxn][maxn];
int f[maxn][maxn];//f[i][j]表示从上往下走到(i,j)的最大路径和
int g[maxn][maxn];//g[i][j]表示从下往上走到(i,j)的最大路径和
int l[maxn][maxn];//(i,j)左边点的最大值
int r[maxn][maxn];//(i,j)右边点的最大值
int main()
{
freopen("tower.in","r",stdin);
freopen("tower.out","w",stdout);
int n,m;
read(n);read(m);
for (int i=1; i<=n; ++i)
for (int j=1; j<=i; ++j)
read(a[i][j]),
f[i][j]=max(f[i-1][j-1],f[i-1][j])+a[i][j];
for (int i=n; i>=1; --i)
for (int j=i; j>=1; --j)
g[i][j]=max(g[i+1][j+1],g[i+1][j])+a[i][j];
for (int i=1; i<=n; ++i)
{
for (int j=1; j<=i; ++j) l[i][j]=max(l[i][j-1],f[i][j]+g[i][j]-a[i][j]);
for (int j=i; j>=1; --j) r[i][j]=max(r[i][j+1],f[i][j]+g[i][j]-a[i][j]);
}
while (m--)
{
int x,y;
read(x);read(y);
if (x==1 && y==1) puts("-1");
else printf("%d\n",max(l[x][y-1],r[x][y+1]));
}
return 0;
}