“多边形游戏”是一款单人益智游戏。
游戏开始时,给定玩家一个具有N个顶点N条边(编号1-N)的多边形,如图1所示,其中N = 4。
每个顶点上写有一个整数,每个边上标有一个运算符+(加号)或运算符*(乘号)。
第一步,玩家选择一条边,将它删除。
接下来在进行N-1步,在每一步中,玩家选择一条边,把这条边以及该边连接的两个顶点用一个新的顶点代替,新顶点上的整数值等于删去的两个顶点上的数按照删去的边上标有的符号进行计算得到的结果。
下面是用图1给出的四边形进行游戏的全过程。
最终,游戏仅剩一个顶点,顶点上的数值就是玩家的得分,上图玩家得分为0。
请计算对于给定的N边形,玩家最高能获得多少分,以及第一步有哪些策略可以使玩家获得最高得分。
输入格式
输入包含两行,第一行为整数N。
第二行用来描述多边形所有边上的符号以及所有顶点上的整数,从编号为1的边开始,边、点、边…按顺序描述。
其中描述顶点即为输入顶点上的整数,描述边即为输入边上的符号,其中加号用“t”表示,乘号用“x”表示。
输出格式
输出包含两行,第一行输出最高分数。
在第二行,将满足得到最高分数的情况下,所有的可以在第一步删除的边的编号从小到大输出,数据之间用空格隔开。
这道题和石子合并非常类似,它的要求是对相邻的元素做合成运算,我们用f[l.r]表示l到r合成一个顶点之后,定点的最大值是多少。
首先这一个问题是一个环的问题,我们要解决环这一类的问题,我们就要把环拆成一个链。然后链的长度要是2n,因为要保证从每一个点开始都可以遍历整个环,所以要将长度乘以2,因为这里面存在着乘法运算,所以我们要求一个区间之间的最值,不能和石子合并的思路一样,直接将q区间分成两部分,然后求两部分的最大值。这样是不对的。因为乘法运算的时候,负负得正,所以可能两个最小的值相乘会变成最大的值。
这样我们就把解决这个题的思路分成了两部分:
首先如果是加法,我们就把我们就把区间的两部分的最大值加加一起。
如果是乘法我们就分别求出左右区间的两个最值,这样就有两个最小值和两个最大值,让他们分别相乘,这样最大值和最小值肯定是其中的两个值。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=110,INF=32768;
int n;
char c[N];
int w[N];
int f[N][N],g[N][N];
int main(){
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>c[i]>>w[i];
c[i+n]=c[i];
w[i+n]=w[i];
}
for(int len=1;len<=n;len++)//枚举区间的长度
for(int l=1;l+len-1<=n*2;l++)//枚举左端点
{
int r=l+len-1;
if(len==1)
f[l][r]=g[l][r]=w[l];
else{
f[l][r]=-INF,g[l][r]=INF;//f表示最大值,g表示最小值,分别赋初值
for(int k=l;k<r;k++)//在区间中寻找分界点
{
char op=c[k+1];
int minl=g[l][k],minr=g[k+1][r],maxl=f[l][k],maxr=f[k+1][r];
if(op=='t')//判断运算符,分别求出最大值和最小值
{
f[l][r]=max(f[l][r],maxl+maxr);
g[l][r]=min(g[l][r],minl+minr);
}
else
{
int x1=minl*minr,x2=minl*maxr,x3=maxl*minr,x4=maxl*maxr;
f[l][r]=max(f[l][r],max(max(x1,x2),max(x3,x4))) ;
g[l][r]=min(g[l][r],min(min(x1,x2),min(x3,x4)));
}
}
}
}
int res=-INF;
for(int i=1;i<=n;i++)
res=max(res,f[i][i+n-1]);
cout<<res<<endl;
for(int i=1;i<=n;i++)
if(res==f[i][i+n-1])
cout<<i<<' ';
return 0;
}