动态规划

LCP 07. 传递信息

awsl,建立动态方程好难阿,我还得在纸上画,然后慢慢推。这个当时没做,幸好我直接关掉那个比赛界面,不然感觉纯粹浪费时间。dp[k][n-1]里存储的表示经过K步到编号为n-1的小朋友的路径数。

int numWays(int n, int** relation, int relationSize, int* relationColSize, int k){//技术型的DP
     const int row=k+1;
    const int col=n;
    int dp[row][col];
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;//这个初始值也很重要

    for(int i=1;i<row;++i){//因为要求必须传递,所以k至少为1
        for(int j=0;j<relationSize;++j)
            //relation[j][1]为目的地,而relation[j][0]为其前一步
            dp[i][relation[j][1]]+=dp[i-1][relation[j][0]];
    }
    return dp[k][n-1];
}

53. 最大子序和

数组增益,其实和注释里的动态方程是一个思想。只不过这样使用的空间小写。
我自己的思维,是一直在意nums[i]对前面和的影响。
而实际是,注意前面和的正负对后面的影响,思维顺序是返的。OMG

#define MAX(x, y) ((x) > (y)) ? (x) : (y)
int maxSubArray(int* nums, int numsSize){//数组增益对后面的影响
    int res=nums[0],i,sum=0;//用sum记录num[i]未参与运算之前的和
    for(i=0;i<numsSize;i++){
        if(sum>0)
            sum+=nums[i];
        else
            sum=nums[i];
        res=MAX(res,sum);//动态方程dp[i]=MAX(dp[i-1]+num[i],num[i])
    }
    return res;
}

322. 零钱兑换

第一话:我要死了,动态规划完全不熟悉,我已经ger屁了。
第二话:我注释的代码,是我整了两个小时,只通过1/3用例的代码,调试了一遍,如果硬币种类中没有1的话,那我的代码就死了,嗯,死了。
第三话:我自己用的二维来解的,后来发现一维就行,因为前面那些行的数据根本就用不到。
最终图解(先看第一张,再看第二张,或许能懂)
在这里插入图片描述
在这里插入图片描述

int Min(int a,int b){
    return a<b? a:b;
}
int coinChange(int* coins, int coinsSize, int amount){//coinsSize为行数,amount为列数
//这是硬币种类被限制,但是每种硬币的数量是没有限制的
   /*int **dp=(int **)malloc(sizeof(int *)*(coinsSize+1));
    int i,j;
    for(i=0;i<=coinsSize;i++){
        dp[i]=(int *)malloc(sizeof(int)*(amount+1));
        memset(dp[i],0,sizeof(int)*(amount+1));
    }
    for(j=0;j<=amount;j++){
        if(j<coins[0])
            dp[0][j]=0;
        else
            dp[0][j]=INT_MAX;
    }
    for(i=1;i<=coinsSize;i++){
        for(j=1;j<=amount;j++){
            if(j>=coins[i-1])
                dp[i][j]=Min(dp[i-1][j],dp[i][j-coins[i-1]]+1);
            else
                dp[i][j]=dp[i-1][j];
        }
    }
    if(dp[coinsSize-1][amount]==0)
        return -1;
    else
        return dp[coinsSize][amount];*/
        if(amount==0)
            return 0;
    int *dp=(int *)malloc(sizeof(int)*(amount+1));
    memset(dp,0,sizeof(int)*(amount+1));
    int i,j,min;
    for(i=0;i<coinsSize;i++){
        for(j=coins[i];j<=amount;j++){
            if(j==coins[i])
                dp[j]=1;
            else if(dp[j]==0&&dp[j-coins[i]]!=0)
                dp[j]=dp[j-coins[i]]+1;
            else if(dp[j-coins[i]]!=0)//注意这个地方我第一次写的dp[j]!=0。dp[j-coins[i]]==0代表不存在组合,直接跳过不变就行
                dp[j]=Min(dp[j],dp[j-coins[i]]+1);
        }
    }
    min=dp[amount];
    free(dp);
    return min==0? -1:min;
}

518. 零钱兑换 II

这题是找组成total有多少种方案
在这里插入图片描述

int change(int amount, int* coins, int coinsSize){
    if(coinsSize==0&&amount!=0)
        return 0;
    else if(coinsSize==0&&amount==0)
        return 1;
    int i,j;
    int *dp=(int *)malloc(sizeof(int)*(amount+1));
    memset(dp,0,sizeof(int)*(amount+1));
    for(j=0;j<=amount;j++){
        if(j%coins[0]==0)
            dp[j]=1;
    }
    for(i=1;i<coinsSize;i++){
        for(j=coins[i];j<=amount;j++){
            dp[j]=dp[j]+dp[j-coins[i]];
        }
    }
    return dp[amount];
}

64. 最小路径和

在这里插入图片描述

int minPathSum(int** grid, int gridSize, int* gridColSize){//先把第一行第一列算出来
    if(gridSize==0)
        return 0;
    int i,j;
    for(i=1;i<gridSize;i++){
        grid[i][0]+=grid[i-1][0];
    }
    for(j=1;j<*gridColSize;j++){
        grid[0][j]+=grid[0][j-1];
    }
    for(i=1;i<gridSize;i++){
        for(j=1;j<*gridColSize;j++){
            if(grid[i-1][j]<grid[i][j-1])
                grid[i][j]+=grid[i-1][j];//状态转移方程
            else
                grid[i][j]+=grid[i][j-1];
        } 
    }
    return grid[gridSize-1][*gridColSize-1];
}

70. 爬楼梯

在这里插入图片描述
分析一下,就是典型的Fibonacci。不好的是,我用递归超时了,然后换成下面的。

int climbStairs(int n){
    if(n<=2)
        return n;
    int pre1=1,pre2=2,i,cur;
    for(i=2;i<n;i++){
        cur=pre1+pre2;
        pre1=pre2;
        pre2=cur;
    }
    return cur;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值