【C++入门】石子合并and数字游戏 记忆化搜索 题解 01版本

关于入门区间DP的递归算法与递推算法比较

第一次用博客,记录错题。

作为一个弱鸡,我认为递归算法比递推好写很多,递推的找条件简直变态,错一个就是0分,还是递归好用

例题: 石子合并:
递归算法:

#include<bits/stdc++.h>
using namespace std;
int n[255],dpmin[1500][1500],dpmax[1500][1500],sum[1500];
int dp_min(int l,int r)//l到r的数合并成一堆 
{
	if(dpmin[l][r]!=-1) return dpmin[l][r];
	if(l==r)return 0;
	int x=1e9;
	for(int i=l;i<r;i++)
	{
		x=min(x,dp_min(l,i)+dp_min(i+1,r)+sum[r]-sum[l-1]);	
	}
	return dpmin[l][r]=x;
}
int dp_max(int l,int r)//l到r的数合并成一堆 
{
	if(dpmax[l][r]!=-1) return dpmax[l][r];
	if(l==r)return 0;
	int x=-1e9;
	for(int i=l;i<r;i++)
	{	
		x=max(x,dp_max(l,i)+dp_max(i+1,r)+sum[r]-sum[l-1]);			
	}
	return dpmax[l][r]=x;
}
int main()
{
	memset(dpmin,-1,sizeof(dpmin));
	memset(dpmax,-1,sizeof(dpmax));
	int num;
	scanf("%d",&num);
	for(int i=1;i<=num;i++)
	{
		scanf("%d",&n[i]);
		n[i+num]=n[i];
	}
	for(int i=1;i<=num+num;i++)
	{
//		dpmin[i][i]=n[i]; dpmax[i][i]=n[i]; 
		sum[i]+=sum[i-1]+n[i];
	}
	int ans=0,ans2=1e9;
	for(int i=1;i<=num;i++)
	{
		 ans=max(ans,dp_max(i,i+num-1));
		 ans2=min(ans2,dp_min(i,i+num-1)); 
	}
	 printf("%d\n%d",ans2,ans);
	 return 0;
}

数字游戏

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
int n,m,a[2005],sum[2005],mi[205][205][15],ma[205][205][15];

int read()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);  
        a[i]=(a[i]%10+10)%10;//处理负数 
        a[i+n]=a[i];//建一个环 
    } 
    for(int i=1;i<=2*n;i++)
        sum[i]=sum[i-1]+a[i];//前缀和 
}

int dfs_min(int l,int r,int k)
{
    if(mi[l][r][k]!=-1)return mi[l][r][k];//记忆化搜索 
    //当k==1时,即分好一个部分,用前缀和计算当前部分区间l-r的权值和 
    if(k==1)return mi[l][r][k]=(sum[r]-sum[l-1])%10;

    int x=inf;
    for(int i=l;i<r;i++) 
	{
		if(i-l+1<k-1)continue;//无效状态 
		x=min(x,dfs_min(l,i,k-1)*dfs_min(i+1,r,1));//[l,i]分k-1份,[i+1,r]分1份 
	}
    return mi[l][r][k]=x;
    //记忆化+return 
}

int dfs_max(int l,int r,int k)//代码理解同上,区别在于这是求 最大 
{
    if(ma[l][r][k]!=-1)return ma[l][r][k];
    if(k==1)return ma[l][r][k]=(sum[r]-sum[l-1])%10;
    int x=0;
    for(int i=l;i<r;i++) 
	{
		if(i-l+1<k-1)continue;//无效状态 
		x=max(x,dfs_max(l,i,k-1)*dfs_max(i+1,r,1));
	}
    return ma[l][r][k]=x;
}

void solve()
{
    memset(mi,-1,sizeof(mi));
    memset(ma,-1,sizeof(ma));
    int maxx=-inf;
    int minn=inf;
    for(int i=1;i<=n;i++)
    {
        maxx=max(maxx,dfs_max(i,i+n-1,m));//在每一种方案下取最大 
        minn=min(minn,dfs_min(i,i+n-1,m));//在每一种方案下取最小
    } 
    printf("%d\n%d\n",minn,maxx);
}

int main()
{
	//freopen("in.txt","r",stdin);
    read();
    solve();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值