20200310之种树 (动态规划 搜索)

题目描述
 A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。
最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。

数据规模和约定

对于全部数据,满足1< =m< =n< =30;
其中90%的数据满足m< =n< =20
-1000< =Ai< =1000

输入
输入的第一行包含两个正整数n、m。
第二行n个整数Ai。

输出
输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”,不包含引号。
样例输入
7 3
1 2 3 4 5 6 7
样例输出
15

转自C语言网大佬题解的动态规划做法:
定义 dp[i][j]dp[i][j] 为 从位置 1 到位置 i 已经种了 j 棵树的情况下,美观度的最大值 (最优值), 索引从 1 开始。

动态转移方程:
dp[i][j] = max(dp[i-2][j-1] + beauty[i], dp[i-1][j])

分别对应位置 i 种树、不种树两种情况。

考虑到 N 个位置成环形,将问题的解分成两种情况以转变为非环形的子问题(从其他位置断开也可以)

1 号位置 种树
则 2、N 位置都不能种树, 问题转化为在 3 ~ N-1 这 N-2个位置上种 M-1棵树, 计算这个子问题时先不考虑1号位置的美观度,这个子问题的最优值为 dp[N-1][M-1] + beauty[1]

1 号位置 不种树
则问题为 在 2 ~ N 这 N-1 个位置上种 M 棵树,这个子问题的最优值为 dp[N][M], 仔细处理边界值

#include <bits/stdc++.h>
using namespace std;
const int minn=-1e9;
const int maxn=31;
int n,m; //n个位置 m棵树 
int beauty[maxn];
int dp[maxn][maxn]; //第几个位置种了几棵树 
int solve(){
	for(int i=1;i<=m-1;i++)
		//1种,则2、n都不种,转化为3~n-1种下m-1棵树 
		dp[1][i]=dp[2][i]=minn;
	for(int i=3;i<n;i++)
		for(int j=1;j<=m;j++)
			dp[i][j]=max(dp[i-2][j-1]+beauty[i],dp[i-1][j]);
	int ans1=dp[n-1][m-1]+beauty[1];
	//1不种
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=m;i++)
		dp[0][i]=dp[1][i]=minn;
	for(int i=2;i<=n;i++)
		for(int j=1;j<=m;j++)
	dp[i][j]=max(dp[i-2][j-1]+beauty[i],dp[i-1][j]);
	int ans2=dp[n][m];
	return max(ans1,ans2);		
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&beauty[i]);
	if(m>n/2){
		printf("Error!");
		return 0;
	}
	printf("%d",solve());
	return 0;
}

大佬题解的搜索做法:

#include <bits/stdc++.h>
using namespace std;
const int maxn=31;
int n,m;       //n个位置,m棵树
int beauty[maxn]; //美化值 
bool isPlanted[maxn];  //是否种上了树
int ans=-1e9,temp=0;  //最优值,临时值
bool check(int pos){ //是否可以种树 
	if(pos>n||isPlanted[pos]||isPlanted[(pos+1)%n]||isPlanted[(pos-1)%n])
		return false;
	 return true;
}
void dfs(int pos,int cnt){ //位置,已经种了几棵树 
	if(cnt==m){
		ans=max(ans,temp);
		return ;
	}
	for(int i=pos;i<=n;i++){
		if(check(i)){  //可种 
			temp+=beauty[i];
			isPlanted[i]=true;
			dfs(i,cnt+1);
			isPlanted[i]=false;
			temp-=beauty[i]; 
		}
	}
} 
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&beauty[i]);
	if(m>n/2){
		printf("Error!");
		return 0;
	}
	dfs(1,0);
	printf("%d",ans);
	return 0;
}
发布了37 篇原创文章 · 获赞 0 · 访问量 371

猜你喜欢

转载自blog.csdn.net/weixin_45351699/article/details/104806321