283. 多边形(区间DP)

该博客主要介绍了如何使用区间动态规划方法解决一个涉及多边形操作的问题。通过对环状序列进行处理,博主逐步计算不同长度子序列的最大值和最小值,特别注意了相乘时可能产生的最大值情况。最终,通过遍历不同长度和分割点,找到全局的最大值,并记录了对应的起始位置。
摘要由CSDN通过智能技术生成

区间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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值