动态规划(一)

文章探讨了多个与IT技术相关的编程问题,包括使用动态规划解决建造房屋、破损楼梯修复、序列构造、洗车时间优化、安全序列计算以及地图路径和电影放映计划的最优化策略。
摘要由CSDN通过智能技术生成

1、建造房屋

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll p = 1e9+7;
int n,m,k; 
ll dp[50][5000];//前i个街道花了j元的方案数 dp[i][j] += dp[i-1][j-v] 
int main(){
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m>>k;
	//因为有至少一个房屋的限制,所以我们先定一个位置
	ll o=m-1,h=k-n;// o 每个街道余下的位置,h 剩余的预算 
	for(ll i=0;i<=h;i++)dp[0][i]=1;// 剩余的预算 最多可以有几个位置 
	for(ll j=0;j<=n;j++)dp[j][0]=1;// 所有的街道起初都要有一个位置 
	
	for(ll i=1;i<=n;i++) {
		for(ll j=1;j<=h;j++){
			if(j>i*o){
				dp[i][j]=dp[i][j-1];
				continue;
			}
			for(ll v=0;v<=j&&v<=o;v++)dp[i][j]=(dp[i][j]+dp[i-1][j-v])%p;
		}
	}
	cout<<dp[n][h];
	return 0;
}

2、破损的楼梯

#include<bits/stdc++.h>
using namespace std;
// dp[i] = dp[i-1] + dp[i-2]
using ll = long long;
const ll p = 1e9+7;
ll n,m,dp[100001],a[100001];
int main(){
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int mm;cin>>mm;
		a[mm]=1;
	}
	dp[0]=1;
	if(!a[1])dp[1]=1;
	for(ll i=2;i<=n;i++){
		if(a[i])continue;
		dp[i]=(dp[i-1]+dp[i-2])%p;
	}
	cout<<dp[n];
	return 0;
}

3、可构造的序列总数

#include <bits/stdc++.h>
using namespace std;
using ll = long long ;
const ll p = 1e9+7;                                 
ll dp[2005][2005];//dp[i][j]表示序列长度为 i,且以 j 结尾的合法序列的数量 
ll ans;
int main(){
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int N,K;cin>>K>>N;
    for(int i=1;i<=K;i++)dp[1][i]=1;//只有1个数,无论是选择1~K中哪个数,都只有1种方案 
    
    for(int i=2;i<=N;i++){//2~N 遍历每一种序列长度
		for(int j=1;j<=K;j++){// 遍历当前序列中最后一个元数的每一种可能 
			for(int k=1;k*k<=j;k++){//遍历每一种可能是j的因子的取值
				if(k*k==j){//偶数,就一个因数  k 
					dp[i][j]=(dp[i][j]+dp[i-1][k])%p; 
				}else if(j%k==0){//说明有两个因数,j/k 和 k 
					dp[i][j]=(dp[i][j]+dp[i-1][j/k]+dp[i-1][k])%p; 
				}	
			}	
		} 
	}
    
    for(int i=1;i<=K;i++){//累加所有长度为N的以1~K结尾的序列数量 
    	ans=(ans+dp[N][i])%p;
	}
	cout<<ans;
    return 0;
}

4、最快洗车时间

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e4+5;
//dp[i][j] 表示前 i 辆车的洗车时间是否需要 j 时间(true or false) 
int tim[109];
bool dp[109][N];
ll n,sum,ans=N;
int main(){
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>tim[i];
		sum=sum+tim[i];//一台机器洗车时间 
	}
	for(int i=0;i<=n;i++)dp[i][0]=true;
	
	for(int i=1;i<=n;i++){//遍历 n 辆车都可能的洗车时间
		for(int j=0;j<=sum;j++){//对于每一种洗车方案,遍历每一种可能的方案
			dp[i][j]=dp[i-1][j];
			if(j>=tim[i])dp[i][j]=dp[i][j]|dp[i-1][j-tim[i]];//选择洗 or 不洗 
		} 	
	} 
	
	for(ll i=1;i<=sum;i++){
		if(dp[n][i]){
			int tmp=max(sum-i,i);
			if(tmp<ans)ans=tmp;
		}
	}
	cout<<ans;
	return 0;
}

5、安全序列

#include<bits/stdc++.h>
using namespace std;
const int p = 1e9+7,N = 1e6+5;
int dp[N],prefix[N];//  dp[i] 表示以位置 i 结尾的方案总数 
int main(){
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int n,k;cin>>n>>k;
	
	dp[0]=prefix[0]=1;
	for(int i=1;i<=n;i++){
		if(i-k-1<1)dp[i]=1;
		else dp[i]=prefix[i-k-1];
		prefix[i]=(prefix[i-1]+dp[i])%p;
	}
	cout<<prefix[n]<<'\n';
	return 0;
}

6、地图

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+3;
char mp[N][N];
int n,m,sk; 
int dp[105][105][2][7];//记忆化数组 
// dp[i][j][0][k] 表示从(i,j)开始,方向向下(1向上),共改变了k次方向,到达终点的方案数量 
bool isnmp(int x,int y){
	return x>0&&x<=n&&y>0&&y<=m;
}
int dfs(int x,int y,int tag,int k){
	int cnt=0;
	if(!isnmp(x,y)||mp[x][y]=='#')return 0;
	if(x==n&&y==m)return 1;
	if(dp[x][y][tag][k])return dp[x][y][tag][k];
	
	if(k<sk){
		cnt=cnt+dfs(x+1,y,1,tag==1?k:k+1);//向下
		cnt=cnt+dfs(x,y+1,0,tag==0?k:k+1);//向右 
	}else if(k==sk){
		if(tag==0){
			cnt=cnt+dfs(x,y+1,tag,k);
		}
		if(tag==1){
			cnt=cnt+dfs(x+1,y,tag,k);
		}
	}
	return dp[x][y][tag][k]=cnt;
}
int main(){
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m>>sk;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>mp[i][j];
	int ans=0;		
	ans=ans+dfs(1,2,0,0);
	ans=ans+dfs(2,1,1,0);
	cout<<ans;
	return 0;
}

7、电影放映计划

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+5,M = 200;
int dp[N],m,n,t[M],w[M],k;
int main(){
	cin>>m>>n;
	for(int i=0;i<n;i++)cin>>t[i]>>w[i];
	cin>>k;
	m+=k;
	for(int i=1;i<=m;i++){
		dp[i]=dp[i-1];
		for(int j=0;j<n;j++){
			if(i>=t[j]+k){
				// dp[i]表示放映时间为i时的最大利润 
				dp[i]=max(dp[i],dp[i-t[j]-k]+w[j]);
			}
		}
	} 
	cout<<dp[m];
	return 0;
}
  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

席万里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值