动归这个算法还是很明显的,首先先对输入的所有操作数和操作符进行保存,第一步,删掉一条边,这个循环遍历,然后接下来的n-1条边每条边和其两个顶点进行删除根据边进行运算将值传递到代替他们的新顶点上,知道所有的边被删除完,剩下的值就是最大值。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxlen=51;
const int maxnum=999999999;
const int minnum=-999999999;
int operand[maxlen]; //操作数
char operat[maxlen]; //操作符
int resmax[maxlen][maxlen]; //i到j合并的最大值
int resmin[maxlen][maxlen]; //i到j合并的最小值
int ansmax; //临时最大值
bool dedge[maxlen]; //最大结果时所删边
int n,i,j,k,steplen,deledge;
int tempmax,tempmin;
void init() //初始化
{
for(i=0;i<n;++i)
for(j=0;j<n;++j)
{
if(i==j) resmax[i][j]=resmin[i][j]=operand[i];
else
{
resmax[i][j]=minnum;
resmin[i][j]=maxnum;
}
}
}
int main()
{
scanf("%d",&n);
for(i=0;i<n;++i)
cin>>operat[i]>>operand[i];
ansmax=minnum;
for(deledge=0;deledge<n;++deledge) //删除一条边
{
init(); //初始化
for(steplen=2;steplen<=n;++steplen) //一条边最短的长度是两个顶点,最长的是n个顶点
{
for(i=deledge;i<=n+deledge-steplen;i++) //从删掉的那条边的一个顶点开始,如果i大于n,再从原来开始
{
j=i+steplen-1; //steplen长度限制
for(k=i;k<j;++k)
{
int kleftmax=resmax[i%n][k%n]; //mod解决i大小限制
int kleftmin=resmin[i%n][k%n];
int krightmax=resmax[(k+1)%n][j%n];
int krightmin=resmin[(k+1)%n][j%n];
if(operat[(k+1)%n]=='t')
{
tempmax=kleftmax+krightmax;
tempmin=kleftmin+krightmin;
}
else
{
tempmax=max(max(kleftmax*krightmax,kleftmin*krightmin),max(kleftmin*krightmax,kleftmax*krightmin));
tempmin=min(min(kleftmax*krightmax,kleftmin*krightmin),min(kleftmin*krightmax,kleftmax*krightmin));
}
resmax[i%n][j%n]=max(resmax[i%n][j%n],tempmax);
resmin[i%n][j%n]=min(resmin[i%n][j%n],tempmin);
}
}
}
if(resmax[deledge][(deledge+n-1)%n]>ansmax) //记录最大值和最大值时所删边
{
memset(dedge,0,sizeof(dedge));
ansmax=resmax[deledge][(deledge-1+n)%n];
dedge[deledge]=1;
}
else if(resmax[deledge][(deledge-1+n)%n]==ansmax)
dedge[deledge]=1;
}
cout<<ansmax<<endl;
for(i=0;i<n;++i)
if(dedge[i]) cout<<i+1<<" ";
return 0;
}