“多边形游戏”是一款单人益智游戏。
游戏开始时,给定玩家一个具有N个顶点N条边(编号1-N)的多边形,如图1所示,其中N = 4。
每个顶点上写有一个整数,每个边上标有一个运算符+(加号)或运算符*(乘号)。
1179_1.jpg
第一步,玩家选择一条边,将它删除。
接下来在进行N-1步,在每一步中,玩家选择一条边,把这条边以及该边连接的两个顶点用一个新的顶点代替,新顶点上的整数值等于删去的两个顶点上的数按照删去的边上标有的符号进行计算得到的结果。
下面是用图1给出的四边形进行游戏的全过程。
1179_2.jpg
最终,游戏仅剩一个顶点,顶点上的数值就是玩家的得分,上图玩家得分为0。
请计算对于给定的N边形,玩家最高能获得多少分,以及第一步有哪些策略可以使玩家获得最高得分。
输入格式
输入包含两行,第一行为整数N。
第二行用来描述多边形所有边上的符号以及所有顶点上的整数,从编号为1的边开始,边、点、边…按顺序描述。
其中描述顶点即为输入顶点上的整数,描述边即为输入边上的符号,其中加号用“t”表示,乘号用“x”表示。
输出格式
输出包含两行,第一行输出最高分数。
在第二行,将满足得到最高分数的情况下,所有的可以在第一步删除的边的编号从小到大输出,数据之间用空格隔开。
数据范围
3≤N≤50,
数据保证无论玩家如何操作,顶点上的数值均在[-32768,32767]之内。
输入样例:
4
t -7 t 4 x 2 x 5
输出样例:
33
1 2
思路:
- 扩展一倍将环变链条。
- f1(i,j)代表从i到j的最大值,f2(i,j)代表从i到j的最小值。要记录最小值是因为可能出现负数的情况。负数乘以负数可能得到更大的负数
- 注意下标。如果按照k为分解点,那么第k+1个位置为符号。而且枚举的时候不能到i+len。因为会超出这个范围。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105;
int f1[maxn][maxn],f2[maxn][maxn];
char s[maxn];
int a[maxn];
int main()
{
int n;scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
getchar();scanf("%c%d",&s[i],&a[i]);
s[i + n] = s[i];
a[i + n] = a[i];
}
memset(f1,-0x3f,sizeof(f1));memset(f2,0x3f,sizeof(f2));
for(int i = 1;i <= 2 * n;i++)
{
f1[i][i] = f2[i][i] = a[i];
}
for(int l = 1;l <= n;l++)
{
for(int i = 1;i + l <= 2 * n;i++)
{
int j = i + l;
for(int k = i;k < j;k++)//不能等于j,因为等于j的话符号就到了j+1位置,就超过这个范围了。
{
if(s[k + 1] == 't')//一开始这里的边界搞错了,应该是k+1位置的符号。
{
f1[i][j] = max(f1[i][j],f1[i][k] + f1[k + 1][j]);
f2[i][j] = min(f2[i][j],f2[i][k] + f2[k + 1][j]);
}
else
{
f1[i][j] = max(f1[i][j],f1[i][k] * f1[k + 1][j]);
f1[i][j] = max(f1[i][j],f2[i][k] * f2[k + 1][j]);
f2[i][j] = min(f2[i][j],f2[i][k] * f2[k + 1][j]);
f2[i][j] = min(f2[i][j],f2[i][k] * f1[k + 1][j]);
f2[i][j] = min(f2[i][j],f1[i][k] * f1[k + 1][j]);
f2[i][j] = min(f2[i][j],f1[i][k] * f2[k + 1][j]);
}
}
}
}
int maxx = -0x3f3f3f3f;
for(int i = 1;i <= n;i++)
{
// printf("%d\n",f1[i][i + n - 1]);
maxx = max(f1[i][i + n - 1],maxx);
}
printf("%d\n",maxx);
for(int i = 1;i <= n;i++)
{
if(f1[i][i + n - 1] == maxx)
{
printf("%d ",i);
}
}
return 0;
}