题解

q 2021-05-04 19:08:32 2021-05-04 19:09:19 0

P3847 [TJOI2007]调整队形

这个题目可以使用动态规划和记忆化搜索

首先考虑记忆化搜索,待会儿考虑如何将记忆化搜索转化成动态规划

的作用是统计~区间让这个区间变成符合要求的操作的最小值

①当时,不需要进行任何操作,返回0

②当时,如果,那么不需要进行任何操作,返回0。不然的话,至少需要进行一次操作,返回1

③当时,返回,就是说返回它本身和它里面一层区间的最小值

④以上条件都不满足,则则需要取还有的最小值,就是说放弃两端,或者放弃左端,或者放弃右端

不多说了,上代码

#include<bits/stdc++.h>
using namespace std;
int n,a[3005],dp[3005][3005];
int dfs(int l,int r){
	if(l==r) return 0;
	if(dp[l][r]!=2139062143) return dp[l][r];
	if(r-l==1){
		if(a[l]==a[r]) return 0;
		else return 1;
	}
	if(a[l]==a[r]) dp[l][r]=min(dp[l][r],dfs(l+1,r-1));
	else dp[l][r]=min(dp[l][r],min(dfs(l+1,r-1)+1,min(dfs(l+1,r)+1,dfs(l,r-1)+1)));
	return dp[l][r];
}
int main(){
	memset(dp,127,sizeof(dp));//记得初始化
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	cout<<dfs(1,n);//最后的答案就是1~n的最小操作次数
	return 0;
}

众所周知,一般情况下,记忆化搜索大部分都是可以转成动态规划的,思路大致差不多,只需要把记忆化搜索的代码改一改,改一改循环的顺序,就可以成功了

在这里,就不细讲了,直接上代码

#include<bits/stdc++.h>
using namespace std;
int n,a[3005],dp[3005][3005];
int main(){
	memset(dp,127,sizeof(dp));
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=n;i>=1;i--)
		for(int j=i;j<=n;j++){
			if(i==j) dp[i][j]=0;
			if(i+1==j){
				if(a[i]==a[j]) dp[i][j]=0;
				else dp[i][j]=1;
			}
			if(a[i]==a[j]) dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
			else dp[i][j]=min(dp[i][j],min(dp[i+1][j-1]+1,min(dp[i+1][j]+1,dp[i][j-1]+1)));
		}
	printf("%d",dp[1][n]);
	return 0;
}

有错还请不吝指正,谢谢!!!

{{ vote && vote.total.up }}

共 4 条回复

Xiongsiming

dfs???

null him

想AFO了!!!

null him

你说你是萌新???谁信啊

q

自己的第一篇题解,还请大佬们过目!!!