这题好像有一些动规的味道。嗯嗯,比较基础的动规题。个人感觉用 O(n2) 的算法可以解决掉。

原题地址:http://poj.org/problem?id=1179

POJ 1179 多边形

问题描述

Polygon 是一个有关多边形的单人游戏。图 1 就是一个这样的多边形,它的边数 N 为 4. 多边形中每一个顶点都标记了一个整数,每一条边都标记了 +(加号)或 *(乘号)。并且,边被标记了从 1 到 N 的整数。

Figure 1

在第一回合的时候,先拿掉多边形的一条边。接下来的回合中涉及以下几步:

  • 选择一条边 E 和它所连接的两个顶点 V1 和 V2;然后……
  • 将它们替换成一个新顶点,并且这个新顶点的标签,就是以 V1 和 V2 所标记的数,在边 E 所标记的符号下运算,所得到的结果。

在没有任何边的时候,游戏结束,并且游戏的得分是最后幸存顶点所标记的数字。

考虑图 1 的多边形。玩家第一回合拿掉了第 3 条边。此后,玩家依次选择了第 1 条边,第 4 条边,最后是第 2 条边。他的得分是 0.

Figure 2

写一个程序,对于给出的多边形,计算其可行的最高得分;并且列出所有能够使得游戏取得最高分的,在第一回合被拿掉的边。

输入数据

你的程序需要从标准输入中读取数据,输入数据将描述这个有 N 个顶点的多边形。输入数据共含两行,第一行就是整数 N. 第二行包含从第 1 条到第 N 条边的标签,并且顶点的标签将会穿插在其中(就是,先给出第 1 条边的符号,然后给出与第 1 条边和第 2 条边共连的顶点的数字,再给出第二条边的符号,依此类推,直到与第 N 条边和第 1 条边共连的顶点),这些数据会以一个空格分隔。边的标签会表示成字母 t(表示加号 +)或字母 x(表示乘号 *)。

3 ≤ N ≤ 50

对于每个回合,输入数据能够保证顶点的标签会在 [-32768, 32767] 范围内。

输出数据

你的程序需要把结果输出到标准输出中。第一行,你的程序应输出该多边形能够得到的最高分。第二行,它必须写出所有能够使得游戏取得最高分的,在第一回合被拿掉的边 (all edges that, if removed on the first move, can lead to a game with that score)。如果有多条边,必须以升序输出,并且以一个空格分隔。

样例输入

4
t -7 t 4 x 2 x 5

样例输出

33
1 2

解题思路

使用一个二维数组 arr[i][j] 存储从 i 到 j 的顶点,若按照规则最终成为一个顶点时,得分的最大值。边缘状态是 arr[i][i] 和 arr[i][i+1], 状态转移是 max { arr[i][k] + arr[k+1][j] } 或者 max { arr[i][k] * arr[k+1][j] }, k∈[i, j), 这取决于那条边是想用乘法还是用加法。最后我们需要从 arr[i][i-1](可认为是 arr[i][i+n])获得最大值,然后再扫一遍它们,确定相应的边即可。

嗯嗯,其实我一开始就是这样想才 WA 的……上面的话不全错,也不全对。

因为题目中涉及了乘号,所以,两个负数可以乘出正数来。所以我们还需要一个数组同时记录阶段最小值,这样状态转移就变得复杂了,这也是这道题难的地方。非常阴险的题目哈。

这题给我的一个教训是,递推有时或许好查错,记忆化递归或许有些难,而且容易 TLE. 还有就是有时需要记一些最差解……差极必优。

源代码

原创文章,转载请注明来源:http://euyuil.com/2353/poj-1179-polygon/