题目链接:http://poj.org/problem?id=1179
翻译:“多边形”是一个关于有N个顶点的多边形的游戏。以图1为例:
这是一个N为4的多边形。每个顶点都代表一个整数,每条边都被一个操作符标记,这个操作符要么是“+”(加号)要么是“*”(乘法)。边由1到N进行标记。
游戏的第一边是去掉一条边。之后的步骤如下:
选择一条边E和它连接的两个顶点V1,V2;
然后用一个新的顶点来取代它们,这个顶点的值是V1和V2所代表的整数,进行了E所代表的运算得到的。
当边全部消除后,这个游戏结束,最终得分为最后那个顶点所代表的整数。
以图1的多边形为例,玩家首先去掉了第三边边,然后选择了第一条边,(进行运算后)再选择了第四条,最后第二条,最终得分为0.
写一个程序,要求在给定一个多边形的情况下,这个程序能算出可能得到的最高分,若先去掉某边能得到这个分数,把这条边标号输出。
状态方程:
//all is the maxans
dis=solve(maxans[i][(i+k)%n],maxans[(i+k+1)%n][(i+j)%n],oper[(i+k+1)%n]);
if(dis>maxans[i][(i+j)%n])maxans[i][(i+j)%n]=dis;
else if(dis<minans[i][(i+j)%n])minans[i][(i+j)%n]=dis;
//all is the minans
dis=solve(minans[i][(i+k)%n],minans[(i+k+1)%n][(i+j)%n],oper[(i+k+1)%n]);
if(dis>maxans[i][(i+j)%n])maxans[i][(i+j)%n]=dis;
else if(dis<minans[i][(i+j)%n])minans[i][(i+j)%n]=dis;
dis其实指的是区间内所能得到的最高分……
all is the maxans和all is the minans与两种情况有关:
首先,如果是加法操作的话,当然直接选两段的最大值,相加就好。
但是,要考虑乘法,如果两段最大值分别为1,3,而最小值为-32和-34,显然两个最小值相乘的总得分会更大。
所以all is the maxans就是考虑两个点都是最大值的情况,all is the minans则是两个点都是最小值的情况。
每种情况算出的dis是i到i+k区间和i+k+1到i+j区间的得分之各,把它与当前i到i+j区间的得分比较,如果比它大,存在maxans里,否则,存在minans里。
由于枚举了删掉某一边的情况,所以要查找答案,看先删掉哪条边复分最高。
AC代码如下:
#include <iostream>
#include<cstdio>
#include<algorithm>
#define MAXN 55
using namespace std;
struct results{
int n;
int result;
};
char oper[MAXN];
int lines[MAXN];
int num[MAXN];
int maxans[MAXN][MAXN],minans[MAXN][MAXN];
int solve(int x, int y, char ope)
{
if(ope=='t')return x+y;
else return x*y;
}
int main()
{
int n;//n numbers in total
cin>>n;
for(int i=0;i<n;i++)
{
cin>>oper[i]>>num[i];
maxans[i][i]=num[i];
minans[i][i]=num[i];
}
//initialization
for(int i=1;i<n;i++)
{
for(int j=0;j<n;j++)
{
maxans[j][(j+i)%n]=solve(maxans[j][j],maxans[(j+1)%n][(j+i)%n],oper[(j+1)%n]);
minans[j][(j+i)%n]=maxans[j][(j+i)%n];
}
}
//dp
int dis;
for(int j=1;j<n;j++)
{
for(int i=0;i<n;i++)
{
for(int k=0;k<j;k++)
{
//all is the maxans
dis=solve(maxans[i][(i+k)%n],maxans[(i+k+1)%n][(i+j)%n],oper[(i+k+1)%n]);
if(dis>maxans[i][(i+j)%n])maxans[i][(i+j)%n]=dis;
else if(dis<minans[i][(i+j)%n])minans[i][(i+j)%n]=dis;
//all is the minans
dis=solve(minans[i][(i+k)%n],minans[(i+k+1)%n][(i+j)%n],oper[(i+k+1)%n]);
if(dis>maxans[i][(i+j)%n])maxans[i][(i+j)%n]=dis;
else if(dis<minans[i][(i+j)%n])minans[i][(i+j)%n]=dis;
}
}
}
//find ans;
int ans=maxans[0][n-1];
int cnt=0;
for(int i=0;i<n;i++)
{
if(maxans[i][(i+n-1)%n]>ans)
ans=maxans[i][(i+n-1)%n];
}
for(int i=0;i<n;i++)
{
if(maxans[i][(i+n-1)%n]==ans)
lines[cnt++]=i;
}
sort(lines,lines+cnt);
printf("%d\n",ans);
//printf("%d*\n",cnt);
for(int i=0;i<cnt-1;i++)
printf("%d ",lines[i]+1);
printf("%d\n",lines[cnt-1]+1);
return 0;
}