(序列型dp)打劫房屋
假设你是一个专业的窃贼,准备沿着一条街(n个房屋)打劫房屋。每个房子都存放着特定金额的钱ai。你面临的唯一约束条件是:相邻的房子装着联系的防盗系统,且当相邻的两个房子同一天被打劫时,该系统会自动报警。
给定房屋数量n,给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。
输入样例:
8
1, 9, 2, 6, 8, 5, 10, 4
输出样例:
27
暴力dfs:
#include<iostream> #include<string.h> #include<math.h> using namespace std; int n,m,v; long ans; int mod=1e9+7; int dp[105][105],aa[105]; bool vis[105]; void dfs2(int pos,int cot,int s){ if(pos==n+1){ if(ans<s){ ans=s; } return; } if(cot==0){ dfs2(pos+1,1,s+aa[pos]); } dfs2(pos+1,0,s); } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>aa[i]; } dfs2(1,0,0); cout<<ans; return 0; }
dp解法:
#include<iostream> #include<string.h> #include<math.h> using namespace std; int n,m,v; long ans; int mod=1e9+7; int dp[105],aa[105]; bool vis[105]; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>aa[i]; } dp[0]=0; //我们设房子从1开始 第0个房子 肯定没法偷 dp[1]=aa[1]; for(int i=2;i<=n;i++){ //首先明白dp[i]表示选了的和 dp[i]=max(dp[i-1],dp[i-2]+aa[i]); //这个转移方程的逻辑是 选不选aa[i]的问题 则要看aa[i-1]是否被选了 } //若是aa[i-1]已经选了 就只能不选a[i] dp[i]=dp[i-1] 但是也可以不从i-1选aa[i] 从dp[i-2]选 dp[i]=dp[i-2]+aa[i] cout<<dp[n]; //若是aa[i-1]没选 a[i]选不选都可 dp[i]=dp[i-1] 或dp[i]=dp[i-2]+aa[i] return 0; }
升级版本:还是原问题,加了一个条件一条街上的首尾两个房子是相连的
输入样例:
3
3 6 4
输出样例:
6
暴力dfs:
#include<iostream> #include<string.h> #include<math.h> using namespace std; int n,m,v; long ans; int mod=1e9+7; int dp[105][105],aa[105]; bool vis[105]; void dfs(int pos,int s){ if(pos==n+1){ if(ans<s){ ans=s; } return; } if(vis[pos-1]!=1&&vis[(pos+1)%n]!=1){ vis[pos]=1; dfs(pos+1,s+aa[pos]); vis[pos]=0; } dfs(pos+1,s); } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>aa[i]; } dfs(1,0); cout<<ans; return 0; }