您的位置:首页 > 其它

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

2020-04-07 12:22 1431 查看

题目描述
 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
[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;
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
是IMI呀 发布了38 篇原创文章 · 获赞 0 · 访问量 714 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: