介绍两道力扣题来引入一下
目录
1.leetcode62-不同路径
首先对于这个题的话肯定是dp求解的(dfs的话肯定是超时的),可以理解为<坐标型动态规划>,下面给大家放一道简单类型的坐标型动态规划然大家先入门一下.(来自于leetcode的第62题-不同路径)
个机器人位于一个 m x n 网格的左上角 ,机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。
问总共有多少条不同的路径
示例 1:
输入:m = 3, n = 7
输出:28
示例 2:
输入:m = 3, n = 2
输出:3
1 <= m, n <= 100
https://leetcode-cn.com/problems/unique-paths
其实这就属于一个坐标系动态规划签到题,做动态规划题一般考虑最后一步就好了,看它可不可以构成最优子结构的问题,下面可以看一下简单的分析
所以有了这些知识点之后我们就可以初步判断出状态转移方程该怎么写了
所以向下延展一下
所以状态转移方程就是f[i][j]=f[i-1][j]+f[i][j-1](i-1>0&&j-1>0);
所以代码就可以是下面这样子(用来滚动数组了,大家以后要养成一个用滚动数组的好习惯,只要现在的关系之和上一层的有关就可以滚动数组啦):
int uniquePaths(int m, int n){
int dp[2][n+1],old=0,now=1;
for(int i=0;i<m;i++)
{
old=now;
now=1-now;
for(int j=1;j<=n;j++)
{
if(i==0||j==1)
{
dp[now][j]=1;
}else{
dp[now][j]=dp[old][j]+dp[now][j-1];
}
}
}
return dp[now][n];
}
然后这个题就结束了,可能有小伙伴要问了,这题和上面那个蓝桥杯国赛题有什么联系吗,再看完下面这道你就明白了。
由于蓝桥杯那道题有障碍物的引入所以咱在来把这个机器人走迷宫加强训练一下,还是leetcode的一道题,只不过加了障碍物
2.leetcode63-不同路径Ⅱ
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
示例 1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
示例 2:
输入:obstacleGrid = [[0,1],[0,0]]
输出:1
https://leetcode-cn.com/problems/unique-paths-ii
其实这道题比上一道题就多了个障碍物这一种要求,然后我们想一下如果碰到障碍物会怎么样?其实啊当我们碰到了障碍物就等于说是不能往前走了,那么此时我们应该将这个点的步数设置成为0,这样就好啦,下面看下代码
int uniquePathsWithObstacles(int** obstacleGrid, int obstacleGridSize,
int* obstacleGridColSize) {
int n = obstacleGridSize, m = obstacleGridColSize[0];
int f[m];
memset(f, 0, sizeof(f));
f[0] = (obstacleGrid[0][0] == 0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (obstacleGrid[i][j] == 1) {
f[j] = 0;
continue;
}
if (j - 1 >= 0 && obstacleGrid[i][j - 1] == 0) {
f[j] += f[j - 1];
}
}
}
return f[m - 1];
}
这里用的应该是leetcode的官方题解,我自己在另一个平台做过了,道理都是一样的
3.质数行者
其实当你理解了上面两道题你就差不多懂了<坐标型动态规划>到底是个什么样的了,对于这道题来说不过就是从二维的变成了三维的而已啦,难度并没有增加很多,首先理解题意,说的是每次只能走“质数”也就是素数,相比较于之前的机器人来说,只不过将往下走和往右走改成了,向北走向右走和向下走,而且每次走的不是一格了,而是质数格,所以此时就必须将素数用数组存起来来维护,这样就比较好计算了,遇到了陷阱就将那个地方的值变成0就可以了。
链接:http://lx.lanqiao.cn/problem.page?gpid=T2882
#include<stdio.h>
#include<string.h>
#define mod 1000000007
int dp[300][300][300]; //这里定义到300了,再大的话就数组爆炸了//
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
int n,m,w,flag=0,Max;
int r1,c1,h1,r2,c2,h2;
scanf("%d%d%d",&n,&m,&w);
memset(dp,0,sizeof(dp));
int arr[1000],i,j,k,l; //arr数组用来记录当前长宽高最大值一下的所有素数//
int MAX=max(n,max(m,w));
arr[0]=0;
arr[1]=2;
k=2;
for(i=2;i<=MAX;i++) //这里的时间复杂度其实可以忽略不及的,因为下面的是n的三次方//
{
for(j=2;j<i;j++)
{
if(i%j==0)
{
break;
}
if(j==i-1)
{
arr[k]=i;
k++;
break;
}
}
}
dp[1][1][1]=1; //这里一定要设置成为1,这是坐标系动态规划的必须//
scanf("%d%d%d%d%d%d",&r1,&c1,&h1,&r2,&c2,&h2);
for(i=1; i<=n; i++)
{
for(j=1; j<=m; j++)
{
for(k=1; k<=w; k++)
{
MAX=max(i,max(j,k)); //用max来将下面的三重循环缩小//
if(i==r1&&j==c1&&k==h1||i==r2&&j==c2&&k==h2) //遇到陷阱的话直接continue然后将这个点的步数设置成为0//
{
dp[i][j][k]=0;
continue;
}
for(l=1; arr[l]<MAX; l++) //计算该点的所有可能性的结果//
{
if(i-arr[l]>0)
{
dp[i][j][k]=(dp[i][j][k]%mod+dp[i-arr[l]][j][k]%mod)%mod;
}
if(j-arr[l]>0)
{
dp[i][j][k]=(dp[i][j][k]%mod+dp[i][j-arr[l]][k]%mod)%mod;
}
if(k-arr[l]>0)
{
dp[i][j][k]=(dp[i][j][k]%mod+dp[i][j][k-arr[l]]%mod)%mod;
}
}
}
}
}
printf("%d",dp[n][m][w]%mod);
return 0;
}
ps:这道题,这个代码是拿不到所有的分数的,因为后面的数组太大了,内存存不下,而且时间复杂度也很高,但是呢又没有什么特别好的办法来进行缩减,但是这个想法是完全正确的,你可以自己带值进去算结果都是正确的,就先理解个思路吧,到后面有时间的话可以把这个题在看看。