查看: 1355| 回复: 6
跳转到指定楼层
上一主题 下一主题
收起左侧

[动态规划] 求助一道算法题

全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
问题描述:




假如有一排房子,共 n 个,每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子, 但是各个颜料是有限的, 红色能够粉刷n_r 房子, 绿色能够粉刷n_g房子, 蓝色能够粉刷n_b房子, 且n_r+n_g+n_b=n

当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x 3 的矩阵来表示的。

例如,costs[0][0] 表示第 0 号房子粉刷成红色的成本花费;costs[1][2] 表示第 1 号房子粉刷成绿色的花费,以此类推。请你计算出粉刷完所有房子最少的花费成本。

思考方向:
dp最终实现O(n^3)

需要帮助的地方:
完全没有dp递推公式的思路, 只想到了列出所有可能的排列(有重复数字的全排列, 回溯+剪枝),,然后比较各个花费的大小, 但是这样的时间复杂度, 是O(n*n!) 太大了!!!!

引用
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/paint-house

上一篇:转码java求战友
下一篇:真心请教地里xdjm关于leetcode内部solver的工作流程
🔗
 楼主| liuyahan 2021-6-9 12:19:08 | 只看该作者
全局:
救救孩子吧!!!!!!
回复

使用道具 举报

全局:
主楼有个typo吧,是O(n*3) (也就是O(n)),O(n^3)就变成n的三次方啦

这个题bottom-up或者top-down都比较好想,看楼主习惯怎么写了,以bottom-up举例:
dp是一个3*n的数组,dp[i][j]表示把房子0-i都涂好颜色,并且房子i涂上颜色j所需要的最小总花费(“总”是指房子0-i的总和)

初始化
对于dp[0][0],既然左边没有任何房子,dp[0][0]就是给0号房子刷颜色0的花费了,没有任何限制条件,dp[0][0] = cost[0][0]
dp[0][1], dp[0][2]同理

接下来考虑递推公式:对于i>=1,dp[i][0]该怎么算
如果想要给房子i刷颜色0,那么唯一的要求就是左侧的房子i-1不能是颜色0(注意我们是从左往右刷房子,所以管房子i-1就行不用管i+1)
那么只有两种情况:房子i-1是颜色1,或者房子i-1是颜色2
对应的花费分别是dp[i-1][1],dp[i-1][2]
那么dp[i][0] = min(dp[i-1][1], dp[i-1][2]) + cost[i][0]
dp[i][1], dp[i][2]同理

最后我们想要的是把所有房子涂好颜色的总花费的最小值
return min(dp[n-1]) 即可 (n是房子数量)

补充内容 (2021-06-09 16:11 +08:00):
编辑
看错题了 尴尬 😂
回复

使用道具 举报

🔗
wisdompeak2 2021-6-9 15:51:25 | 只看该作者
全局:
本帖最后由 wisdompeak2 于 2021-6-9 15:56 编辑

非常套路的DP。
令dp【i】【r】【g】[i]表示前i座房子刷出r个红色和g个绿色,所需要的最小代价。显然,前i座房子里刷出的蓝色的个数就是i-r-g(以1-index计数)。
状态转移的关键是第i座房子刷什么颜色,可以是红绿蓝的任意一种。所以
[i][i]dp【i】【r】【g】= min (dp[i-1][r-1][g] + cost[r], dp[i-1][r][g-1] + cost[g], dp[i-1][r][g] + cost)[/i]
[i]
最终的答案是在dp[n][r][g]中,遍历r和g,找到最小的值。特别注意,在dp【i】【r】【g】[i][i]的三重循环中,r、g、i-r-g都不能超过各自的上限nr、ng、nb。
[/i][/i][/i][/i][/i]
回复

使用道具 举报

🔗
 楼主| liuyahan 2021-6-9 23:08:17 | 只看该作者
全局:
boruwang 发表于 2021-6-9 13:12
主楼有个typo吧,是O(n*3) (也就是O(n)),O(n^3)就变成n的三次方啦

这个题bottom-up或者top-down都比较 ...

是的是的,条件是n_r, n_g, n_b, 不是相邻的房子颜色不同,感谢回复啦!!!!!!!!
回复

使用道具 举报

🔗
 楼主| liuyahan 2021-6-9 23:11:12 | 只看该作者
全局:
wisdompeak2 发表于 2021-6-9 15:51
非常套路的DP。
令dp【i】【r】【g】表示前i座房子刷出r个红色和g个绿色,所需要的最小代价。显然,前i座 ...

啊是的,之前没有想过可以增加dp array的维度,一直卡在怎么存储使用的颜料数量,感谢大佬!!
回复

使用道具 举报

🔗
twtypsj 2021-6-10 12:49:19 | 只看该作者
全局:
大概写了一下,求大米

  1. int paintHouseDP(vector<vector<int>> cost, vector<int> count)
  2. {
  3.     int n = cost.size();
  4.     vector<vector<vector<int>>> dp(count[0]+1, vector<vector<int>>(count[1]+1, vector<int>(count[2]+1, INT_MAX)));
  5.     int res = INT_MAX;
  6.     dp[0][0][0] = 0;
  7.     for(int i=1; i<=n; ++i)
  8.     {
  9.         for(int r=0; r<=min(i, count[0]); ++r)
  10.         {
  11.             for(int g=0; g<=min(i-r, count[1]); ++g)
  12.             {
  13.                 int b = i-r-g;
  14.                 if(b>count[2]) continue;
  15.                 if(r) dp[r][g][b] = min(dp[r][g][b], dp[r-1][g][b]+cost[i-1][0]);
  16.                 if(g) dp[r][g][b] = min(dp[r][g][b], dp[r][g-1][b]+cost[i-1][1]);
  17.                 if(b) dp[r][g][b] = min(dp[r][g][b], dp[r][g][b-1]+cost[i-1][2]);
  18.                 if(i==n) res = min(res, dp[r][g][b]);
  19.             }
  20.         }
  21.     }
  22.     return res;
  23. }
复制代码



评分

参与人数 1大米 +2 收起 理由
liuyahan + 2 给你点个赞!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表