首页 > 其他 > 详细

luogu3146 248G 区间dp

时间:2020-03-17 19:01:38      阅读:58      评论:0      收藏:0      [点我收藏+]

题目链接:https://www.luogu.com.cn/problem/P3146

这题一开始我想的状态是f[i][j]表示从i合并到j的最大值

方程就是如果f[i][l]=f[l+1][j],f[i][j]=max(f[i][j],f[i][l]+1);否则f[i][j]=max(f[i][j],max(f[i][l],f[l+1][j]));

但这是不对的,因为后面一个式子可能导致f[i][j]得出了一个值,但这个值是从子区间里选的,即使f[i][j]和某个区间相等也不一定能合并。

举个例子:3 1 2 2-->3 1 3是正确的合并,答案为3,但方程会这样执行: 3 1 2 2-->3 1 3-->3 3-->4

于是又沙雕的开了一个数组v,v[i][j]=1表示能从i合并到j,v[i][j]=0表示不能,每次合并前先判断一下子区间的v是不是为1。脑补一下感觉问题不大,实际上也过了。

贴个代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=250+10;
int f[maxn][maxn],v[maxn][maxn],a[maxn];
int n,i,j,k,t,m,l;

int main(){
	cin>>n;
	for (i=1;i<=n;i++) cin>>a[i];
	memset(f,0,sizeof(f));memset(v,0,sizeof(v));
	for (i=1;i<=n;i++) {
		f[i][i]=a[i];v[i][i]=1;
	}
    for (k=1;k<=n-1;k++) //*** 
      for (i=1;i<=n-1;i++)
	    if (i+k<=n){
	    	j=i+k;
	    	for (l=i;l<=j-1;l++)
	    	  if (v[i][l]==1&&v[l+1][j]==1){ //若都是完全合并,则分为两堆相等和两堆不等 
	    	  	 if (f[i][l]==f[l+1][j]){
	    	  	    if (f[i][l]+1>=f[i][j]){
	    	  	   	    f[i][j]=f[i][l]+1;v[i][j]=1;
				      }
				    }
				    else{
					    m=max(f[i][l],f[l+1][j]);
						if (m>f[i][j]){
							f[i][j]=m;v[i][j]=0;
						}	
					}
			    } 
			    else{ //如果不都是完全合并 
			    	m=max(f[i][l],f[l+1][j]);
						if (m>f[i][j]){
							f[i][j]=m;v[i][j]=0;
						}	
				}
		}
	cout<<f[1][n]<<endl;
	return 0;
}

  

后来在洛谷上看题解时,看到一种更好的状态,是f[i][j]表示从i合并到j且全部合并,能得到的最大值。因此f[i][j]可以为0(i到j不能全部合并)

转移方程:若f[i][l]=f[l+1][j](l为分割点),f[i][j]=max(f[i][l]+1,f[i][j]),并同时更新答案ans=max(ans,f[i][j])。

贴个代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=250+10;
int a[maxn],f[maxn][maxn];  //f[i][j]表示将i~j *全部* 合并能得到的最大值 
int n,i,j,k,ans,l;

int main(){
	cin>>n;
	ans=0;memset(f,0,sizeof(f));
	for (i=1;i<=n;i++){
		cin>>a[i];f[i][i]=a[i];
		ans=max(ans,a[i]);
	}
	for (k=1;k<=n-1;k++)
	  for (i=1;i<=n-1;i++)
	    if (i+k<=n){
	    	j=i+k;
	    	for (l=i;l<=j-1;l++)
	    	  if (f[i][l]==f[l+1][j]&&f[i][l]!=0&&f[l+1][j]!=0){ //若f[i][l]=0;说明区间[i,l]不能全部合并,f[i+1][j]同理 
	    	  	f[i][j]=max(f[i][j],f[i][l]+1);
	    	  	ans=max(ans,f[i][j]);  //随时更新答案,因为答案不一定为f[1][n] 
			  }
		}
	cout<<ans<<endl;
	return 0;
}

  

luogu3146 248G 区间dp

原文:https://www.cnblogs.com/edmunds/p/12512402.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!