区间DP
283. 多边形
先将环断开加倍,得到的链上可计算所有情况
将区间长度从小到大,从左到右计算
区间[ i ][ j ]遍历分割点求得最大值与最小值
不能省略求区间最小值,最大值可能是由两个最小值相乘得出
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=32767;
char a[110];//存入字符t或者x
int b[110],f[2][110][110],c[110];//f[0][i][j]为i到j最小值,f[1][i][j]为i到j最大值
int main()
{
int i,j,k,n,m,len,maxx=-INF;
scanf("%d",&n);
getchar();
for(k=0;k<=1;k++)//初始化
{
for(i=1;i<=n+n;i++)
{
for(j=1;j<=n+n;j++)
{
if(k==0) f[k][i][j]=INF;//求最小值的初始化最大
else f[k][i][j]=-INF;//求最大值的初始化最小
}
}
}
for(i=1;i<=n;i++)
scanf("%c %d",&a[i],&f[0][i][i]),getchar();
for(i=n+1;i<=n+n;i++)
a[i]=a[i-n],f[0][i][i]=f[0][i-n][i-n];//将数组拉长,使得在再拉长的数组上可求所有的情况
for(i=1;i<=n+n;i++)
{
f[1][i][i]=f[0][i][i];//f[1][][]初始化
}
for(len=2;len<=n;len++)//遍历数字个数的长度
{
for(i=1;i<=n+n-len;i++)//左端点的起始位置和终止位置
{
j=i+len-1;//右端点终止位置
for(k=i;k<j;k++)//分割点的位置
{
if(a[k+1]=='t')//相加时,最大值最小值为各自区间相加
{
f[1][i][j]=max(f[1][i][j],f[1][i][k]+f[1][k+1][j]);
f[0][i][j]=min(f[0][i][j],f[0][i][k]+f[0][k+1][j]);
}
else//相乘时,可能性有四种,注意两个负数相乘得到最大值
{
int x1=f[0][i][k]*f[0][k+1][j];
int x2=f[1][i][k]*f[0][k+1][j];
int x3=f[0][i][k]*f[1][k+1][j];
int x4=f[1][i][k]*f[1][k+1][j];
f[1][i][j]=max(f[1][i][j],max(max(x1,x2),max(x3,x4)));
f[0][i][j]=min(f[0][i][j],min(min(x1,x2),min(x3,x4)));
}
}
if(len==n)
{
if(f[1][i][j]>maxx) maxx=f[1][i][j],c[0]=1,c[1]=i;//存入标记点
else if(f[1][i][j]==maxx) c[++c[0]]=i;
}
}
}
printf("%d\n",maxx);
for(i=1;i<=c[0];i++)
printf("%d ",c[i]);
return 0;
}