题目大意:
多边形游戏,有N个顶点的多边形,3 <= N <= 50 ,多边形有N条边,每个顶点中有一个数字(可正可负),每条边上或者是“+”号,或者是“*”号。边从1到N编号,首先选择一条边移去,然后进行如下操作:
1 选择一条边E和边E连接着的两个顶点V1,V2。
2 用一个新的顶点代替边E和V1、V2,新顶点的值为V1、V2中的值进行边上代表的操作得来(相加或相乘)
当最后只剩一个顶点,没有边时,游戏结束。现在的任务是编程求出最后的顶点能获得的最大值,以及输出取该最大值时,第一步需移去的边,如果有多条符合条件的边,按编号从小到大输出
题目分析:
求获得的最大值,是个dp的过程,dp[i][j]=max(dp[i][k](opt操作)dp[k+1][j])表示从i到j能获得最大值,也就是合并k和k+1
考虑到dp[i][j]是一段区间的最大值,每次dp会重复利用到里面的值,所以用记忆化搜索。
其中的最大值,可能由最小值得到,所以要同时保存最小值。
其中每次dfs(i,i+n-1),也就是断开i-1和i,dp一个以i开头的长度为N的链。
总结一下:这道题是一个区间dp的题目,并且是个环,所以在dp的时候要注意,处理的时候对于>n的对n进行取余。
核心代码
for(int i=l;i<r;i++)
{
q1=dfs(l,i),q2=dfs(i+1,r);
Max=max(Max,);
Min=min(Min,);
}
return dp[l%n][r%n]=make_pair(Max ,Min);
如下标准代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#define N 310
#define LL long long
const long long INF = (LL)1<<59;
inline LL getmax(LL a,LL b)
{
return a<b?b:a;
}
inline LL getmin(LL a,LL b)
{
return a<b?a:b;
}
using namespace std;
int n,m;
pair<LL,LL> dp[N][N];
long long num[N],ans=0;
char G,opt[N];
vector<int>VV;
inline pair<LL,LL> dfs(int l,int r)
{
if(l==r)
return make_pair(num[l%n],num[r%n]);
if(dp[l%n][r%n].first!=INF)
return dp[l%n][r%n];
LL Max=-INF,Min=INF,res;
pair<LL,LL> p1,p2;
for(int i=l;i<r;i++)
{
res=0;
p1=dfs(l,i),p2=dfs(i+1,r);
if(opt[(i+1)%n]=='t')
{
res=p1.first+p2.first;
Max=getmax(Max,res);
res=p1.second+p2.second;
Min=getmin(Min,res);
}
else
{
res=p1.first*p2.first;
Max=getmax(Max,res);
res=p1.second*p2.second;
Max=getmax(res,Max);
res=p1.first*p2.second;
Max=getmax(res,Max);
res=p1.second*p2.first;
Max=getmax(res,Max);
res=p1.first*p2.second;
Min=getmin(Min,res);
res=p2.first*p1.second;
Min=getmin(Min,res);
res=p1.second*p2.second;
Min=getmin(Min,res);
res=p1.first*p2.first;
Min=getmin(Min,res);
}
}
return dp[l%n][r%n]=make_pair(Max,Min);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
dp[i][j].first=dp[i][j].second=INF;
for(int i=0;i<n;i++)
cin>>opt[i]>>num[i];
LL ans=-INF;
for(int i=0;i<n;i++)
{
LL tem=dfs(i,i+n-1).first;
if(tem>ans)
{
ans=tem;
VV.clear();
VV.push_back(i+1);
}
else if(tem==ans)
{
VV.push_back(i+1);
}
}
printf("%lld\n",ans);
for(int i=0;i<(int)VV.size();i++)
{
printf("%d%s",VV[i],i==(VV.size()-1)?"\n":" ");
}
}
while(1);
return 0;
}