树塔狂想曲tower

树塔狂想曲(tower)

【问题描述】

相信大家都在长训班学过树塔问题,题目很简单求最大化一个三角形数塔从上往下走的路径和。走的规则是:(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。

【输入样例】

5 3

1

3 8

2 5 0

1 4 3 8

1 4 2 5 0

2 2

5 4

1 1

【输出样例】

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!

【数据规模】所有测试数据范围和特点如下:对于所有数据,数塔中的数 X 的大小满足




var n,m,i,j,x,y,q,cas:longint;a:array[0..1010,0..1010]of longint;
    dp,dp1,f,g:array[0..1010,0..1010]of int64;
function max(a,b:longint):longint;
begin
   if a>b then exit(a);
   exit(b);
end;
begin
   assign(input,'tower.in');reset(input);
   assign(output,'tower.out');rewrite(output);
   readln(n,m);
   for i:=1 to n do
   begin
      for j:=1 to i do read(a[i][j]);
      readln;
   end;
   for i:=1 to n do
      for j:=1 to i do dp[i][j]:=max(dp[i-1][j],dp[i-1][j-1])+a[i][j];
   for i:=n downto 1 do
      for j:=1 to i do dp1[i][j]:=max(dp1[i+1][j],dp1[i+1][j+1])+a[i][j];
   for i:=1 to n do
   begin
      for j:=1 to i do f[i][j]:=max(f[i][j-1],dp[i][j]+dp1[i][j]-a[i][j]);
      for j:=i downto 1 do g[i][j]:=max(g[i][j+1],dp[i][j]+dp1[i][j]-a[i][j]);
   end;
   for cas:=1 to m do
   begin
      readln(x,y);
      if(x=1)and(y=1)then begin writeln(-1);continue;end;
      q:=max(f[x][y-1],g[x][y+1]);
      writeln(q);
   end;
   close(input);close(output);
end.


你可能感兴趣的:(动态规划,OI)