(动态规划)dp转移方程以及入门题以及题目(库)

博主分享动态规划的学习心得,通过记录每次遇到的dp问题及转移方程进行积累。文章中包含两道动态规划题目,分别是哈尔滨工程大学第十四届程序设计竞赛的F题和西北大学集训队选拔赛的B题,解析了题意和解题思路,并提供了AC代码。博主强调了dp状态转移在解决这类问题中的重要性,并表示会持续更新更多题目。

每次被动态规划的问题给搞死掉!

所以打算每次把dp转移的方程写下来! 然后慢慢积累吧! 也希望分享给大家!

动态规划第一题

题目传送门:哈尔滨工程大学第十四届程序设计竞赛(同步赛)F题
题意: 一个迷宫,然后从(1,1)走到(n,n),只能往下或者右边走!然后每次走的map【i】【j】表示的就是你需要花费这么多代价,然后每次换一个方向,
小帆帆第一次改变方向的费用是 1,第二次的费用是 2,第三次的费用是
4,…… 第 K 次的费用是2^(?−1)。
思路: 我一开始是bfs!然后呢WA,最后看了下dp解。。。
dp[x][y] [ 转移的次数 ][方向的状态]: 表示的就是走到(x,y)位置转移方向k次的最小花费!
所以有: dp[i][j][k][0] = min(dp[i-1][j][k][0],dp[i][j-1][k-1][1]+(1<<k-1))+maps[i][j];

AC代码:

#include<bits/stdc++.h>

typedef long long int ll;
using namespace std;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x;
}
ll minn(ll a, ll b){
	if(a>b){
		return b;
	}else{
		return a;
	}
}
int ans,n;
int sa[105][105]; 
//	dp[x][y][转移次数][方向] 
//	dp[i][j][k][0/1]	表示的是到 (i,j)的位置  变换k次方向的时候 最小话费 0 1 表示的就是方向 
int dp[105][105][25][2];
int main(){
	int t;
	t = read();
	int k =3;
	while(t--){
		ans = 2e9;
		n = read();
		for(int i = 1; i <= n; i++)
			for(int j  = 1; j <= n; j++)
				sa[i][j] = read();
		memset(dp,0x3f3f,sizeof(dp));
		// 初始化为 注意边界就行 
		dp[1][1][0][1] = dp[1][1][0][0] =sa[1][1];
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= n; j++){
				if(i == 1&&j ==1)	continue;
				int cc = sa[i][j];
				dp[i][j][0][0] = dp[i-1][j][0][0] +cc;
				dp[i][j][0][1] = dp[i][j-1][0][1] +cc;
				for(int k = 1; k<=24; k++){
				 
					dp[i][j][k][0] = min(dp[i-1][j][k][0],dp[i][j-1][k-1][1]+(1<<k-1))+cc; 
					// 当前的位置的最小值  就是前面同一个方向 或者是不同的方向 那么就该加上 1<<k-1 
					dp[i][j][k][1] = min(dp[i][j-1][k][1],dp[i-1][j][k-1][0]+(1<<k-1))+cc;
				}
			}
		for(int i = 0; i <=24; i++){
			ans = minn(ans,minn(dp[n][n][i][1],dp[n][n][i][0]));	//这里就是求最后的(n,n)位置,但是不知道是方向方向,还有转了多少次的方向 
		} 
		cout<<ans<<endl;
	}
	return 0;
}

动态规划第二题

动态规划第一题

题目传送门:西北大学集训队选拔赛(重现赛)B题拯救地球(动态规划)
题意: 告诉你有n个救援队,然后m个发动机坏了,需要去救援至少k个,才算是成功,然后每个救援队成功的概率是p,求最后成功概率
思路: 当然就是写出转态转移方程,dp【i】【j】表示的就是到第i个发动机的时候,成功启动j个发动机的概率,然后…(一个发动机成功概率:1-所有救援队失败的概率)

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;

typedef long long int ll;
typedef unsigned long long ull;

void read(int  &x)
{
  	int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
double dp[2005][2005];
int main(){
	
	int n, m, k, x;
	double cc;
	double sa[2005];
	read(n), read(m), read(k);
	for(int i = 1; i <= m; i++)	sa[i] = 1.0;
	for(int i = 1; i <= n; i++){
		cin>>x>>cc;
		sa[x] =sa[x] *(1-cc);
	}
	for(int i = 1; i <= m; i++) sa[i] = 1.0 - sa[i];
	dp[0][0] = 1;
	for(int i = 1; i <= m; i++){
		dp[i][0] = dp[i-1][0] *(1-sa[i]);
		for(int j = 1; j <= m; j++){			//一共就m个机器 
			dp[i][j] = dp[i-1][j-1]*sa[i] + dp[i-1][j]*(1-sa[i]);
		}
	}
	double ans = 0;
	for(int i = k; i <= m; i++){
		ans += dp[m][i]; 
	} 
	printf("%.3lf\n",ans);
	return 0;
} 

持续更新!!!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值