打卡(23)extra

https://leetcode-cn.com/problems/paint-house-iii/
这个动态规划,没太想明白,是怎么能想出来这样动态规划的

class Solution {
public:
    const int INF = 0x3f3f3f3f; 
    int f[105][25][105];
    int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
        for(int i = 0; i <= m; i++){
            for(int j = 0; j <= n; j++){
                f[i][j][0] = INF;//0是不可能
            }
        }
        //动态规划的特点之一是在于,每次都是从前向后递推,同时不会修改任何和当前ijk无关的数值
        for(int i = 1; i <= m; i++){
            int color = houses[i - 1];//当前颜色
            for(int j = 1; j <= n;j++){
                for(int k = 1; k <= target; k++){//最多到达target
                    if(k > i){//明显不合理跳出
                        f[i][j][k] = INF;
                        continue;
                    }
                    //第i个房间已经上色
                    if(color != 0){
                        if(j == color){
                            int cur = INF;
                            for(int p = 1; p <= n; p++){
                                if(p != j){ //颜色不同
                                    cur = min(cur,f[i - 1][p][k - 1]);//颜色不相同,则第三元素取值为k-1
                                }
                            }
                            f[i][j][k] = min(cur,f[i - 1][j][k]);//因为颜色相同,则第三元素取值为k
                        }//颜色相同
                        else f[i][j][k] = INF; //颜色不同则无效
                    }    
                    else{ //第i个房间未上色
                        int u = cost[i - 1][j - 1];
                        int cur = INF;
                        for(int p = 1; p <= n; p++){
                            if(p != j){ 
                                cur = min(cur,f[i - 1][p][k - 1] + u);
                            }
                        }
                        f[i][j][k] = min(cur,f[i - 1][j][k] + u);
                    }   
                }
            }
        }
        int ans = INF;
        for(int i = 1; i <= n; i++){
            ans = min(ans,f[m][i][target]);//从所有的涂色方法中中选择一个最小的输出
        }
        return ans == INF ? -1 : ans;
    }
};

f[i][j][k]表示从0~i的区间里面,最后一个颜色是j,此时形成状态为k个街区情形的最小花费。
我早有预感,状态转移方程可能是三位的,这样来清晰的说明一下,首先必须包含一个k是用来表示几个街区的,其次必须有一个或者两个位是用来表示范围的[i,j]或者[0,i].
那么究竟是哪一种,通过看实际意义来得到。还有一位是表示颜色的。
这样梳理的话,倒是感觉清晰了不少。
状态转移方程:
h o u s e s [ i ] = = 0 d p [ i ] [ j ] [ k ] = m i n p ! = j { d p [ i − 1 ] [ p ] [ k − 1 ] + c o s t [ i ] [ j ] , d p [ i − 1 ] [ j ] [ k ] + c o s t [ i ] [ j ] } houses[i]==0\\ dp[i][j][k]=min_{ p!=j}\{dp[i-1][p][k-1]+cost[i][j],dp[i-1][j][k]+cost[i][j] \} houses[i]==0dp[i][j][k]=minp!=j{dp[i1][p][k1]+cost[i][j],dp[i1][j][k]+cost[i][j]}
h o u s e s [ i ] ! = 0 d p [ i ] [ j ] [ k ] = m i n p ! = j { d p [ i − 1 ] [ p ] [ k − 1 ] , d p [ i − 1 ] [ j ] [ k ] } houses[i]!=0\\ dp[i][j][k]=min_{ p!=j}\{dp[i-1][p][k-1],dp[i-1][j][k] \} houses[i]!=0dp[i][j][k]=minp!=j{dp[i1][p][k1],dp[i1][j][k]}

这样通过总结就可以得到,两者其实只是差了一个cost的值。
所以,可以进一步优化代码。

class Solution {
public:
    const int INF = 0x3f3f3f3f; 
    int f[105][25][105];
    int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
        for(int i = 0; i <= m; i++){
            for(int j = 0; j <= n; j++){
                f[i][j][0] = INF;//0是不可能
            }
        }
        for(int i = 1; i <= m; i++){
            int color = houses[i - 1];//当前颜色
            for(int j = 1; j <= n;j++){
                for(int k = 1; k <= target; k++){//最多到达target
                    if(k > i||j!=color&&color!=0){//明显不合理跳出
                        f[i][j][k] = INF;
                        continue;
                    }
                    int u = cost[i - 1][j - 1];
                    int cur = INF;
                    if(color!=0) u=0; 
                    for(int p = 1; p <= n; p++){
                        if(p != j){ 
                            cur = min(cur,f[i - 1][p][k - 1]+u);
                        }                        
                    }
                    f[i][j][k] = min(cur,f[i - 1][j][k]+u);
                }
            }
        }
        int ans = INF;
        for(int i = 1; i <= n; i++)
            ans = min(ans,f[m][i][target]);
        return ans == INF ? -1 : ans;
    }
};

so,希望我的努力有效且真实。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值