【逃离农场】牛牛在农场饲养了n只奶牛,依次编号为0到n-1, 牛牛的好朋友羊羊帮牛牛照看着农场.有一天羊羊看到农场中逃走了k只奶牛,但是他只会告诉牛牛逃走的k 只奶牛的编号之和能被n整除。你现在需要帮牛牛计算有多少种不同的逃走的奶牛群。因为结果可能很大,输出结果对1,000,000,007取模。

例如n = 7 k = 4: 7只

奶牛依次编号为0到6, 逃走了4只

编号和为7的有:{0, 1, 2, 4}

编号和为14的有:{0, 3, 5, 6}, {1, 2, 5, 6}, {1, 3, 4, 6},{2, 3, 4, 5}

4只牛的编号和不会大于18,所以输出5.

输入描述: 输入包括一行,两个整数n和k(1 ≤ n ≤ 1000),(1 ≤ k ≤ 50),以空格分割。

输出描述: 输出一个整数表示题设所求的种数。

解析:

使用dp[i][j][t]表示前i+1头奶牛中选取j头的和除以n余为t的方案数。

则方案分为两种:选取了第i头奶牛和没有选取第i头奶牛两个子问题

状态控制方程为:dp[i][j][t]=dp[i−1][j][t]+dp[i−1][j−1][((t+n)−i)%n]

不用空间压缩的算法:

int func(int n, int k) {vector<vector<vector<int>>> dp;vector<int> vec1(n,0);   //余数的范围0~n-1共n个,全部初始化为0vector<vector<int>> vec2;vec2.resize(k+1,vec1); // 逃跑o~k只dp.resize(n,vec2);  // n只牛//初始赋值 ,i = 0时, 存在1头牛,选出0个,余n为0,这是一种唯一方案; //选出1个,余n为0,也是一种唯一方案dp[0][1][0] =dp[0][0][0] = 1;//编号为i的前i+1头奶牛for (auto i = 1; i < n; i++) {//选择j头奶牛。注意j的退出条件是min(k,i+1),因为i对应有i+1头牛for (auto j = 0; j <= min(k, i+1); j++){for (auto t = 0; t < n; ++t)//余t{//因为这里会涉及到 j-1,需要确保它大于0if (j > 0){ dp[i][j][t] = (dp[i-1][j][t] + dp[i-1][j - 1][((t + n) - i) % n]);} else{//当j==0的时候,也就是一头牛都没逃走,这时余数必须是0才有值,取其他都是0if (j == 0 && t==0){ dp[i][j][t] = 1;}}}}}return dp[n-1][k][0];
}

注意初始化条件和j的退出条件

留意到状态转移方程,其实每次计算新的i的时候,它只会用到i-1的二维数组的值。所以可以只使用一个二维数组去保存状态值就行了。所以状态方程可以写成

dp[j][t] = (dp[j][t] + dp[j - 1][((t + n) - i) % n]);
int func2(int n, int k) {vector<vector<int>> dp;vector<int> vec(n,0);dp.resize(k + 1, vec);dp[1][0] = dp[0][0] = 1; //网上有些写法,只写了dp[0][0] = 1其实是不对的for (auto i = 1; i < n; i++)//前i+1头奶牛{for (auto j = min(k, i+1); j > 0; --j)//选择j头奶牛。{for (auto t = 0; t < n; ++t)//余t{dp[j][t] = (dp[j][t] + dp[j - 1][((t + n) - i) % n]) ;}}}return dp[k][0];
}

注意:j要使用递减的方式,因为状态方程依赖于j-1,如果我们使用递增,就会先计算了j-1,然后再计算j,这样,j-1就变成了当前i循环的j-1,而不是上一次i循环的j-1。比如先计算i=3,当计算i=4时,先计算j-1,计算完了j-1之后,然后你再计算j的时候,i=3的j-1已经被覆盖,你使用的就是i=4的j-1,这是不对的。所以一定要用递减的方式循环j

[dp算法]逃离农场相关推荐

  1. boost::geometry模块多边形DP算法简化示例

    boost::geometry模块多边形DP算法简化示例 实现功能 C++实现代码 实现功能 boost::geometry模块多边形DP算法简化示例 C++实现代码 #include <boo ...

  2. dp笔记:关于DP算法和滚动数组优化的思考

    从网上总结了一些dp的套路以及对滚动数组的一些思考,现记录如下,希望以后回顾此类算法时会有所帮助. 目录 1.DP算法经验 1.DP算法核心: 2.DP算法类别以及例题 例1:三步问题 例2:最小路径 ...

  3. Leetcode 64. 最小路径和 -- DP算法

    Time: 20190831 题目描述 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 示例: 输入: ...

  4. AIS数据压缩-改进的DP算法(Improved DP algorithm)

    在上两篇博客中,对AIS数据进行压缩用了两种方法: 1.AIS数据压缩-时间比率算法(Time-Ratio-algorithm) 2.AIS数据压缩-时间比率_速度_航向算法(Time-Speed-H ...

  5. 灰度图像压缩 DP算法 位运算详解

    作者码字不易,白天敲代码,晚上熬夜赶报告,要转载请注明出处哦,程序猿的辛酸泪 目录 位运算回顾 压缩过程 解压过程 关于一个莫得感情的小bug 实用小工具的下载地址 完整版代码 位运算回顾 若 a = ...

  6. 第十四周DP算法总结

    这周自己主要再看DP算法的博客,感觉DP这一部分内容确实比之前的都要麻烦一些,最后攻克这一部分难题还是挺好的. 这周自己总结了一些题型,以及一些方法思路,最后再把动态规划和之前的分治和贪心做一下比较. ...

  7. 模式识别读书报告---关于DP算法的…

    我喜欢玩星际争霸,当我操作我的部队用快捷键A进攻敌人时,部队就会自动避开障碍物attack目标.当时我就对为什么部队能自动选择最短的路进攻产生了兴趣,它是用什么算法实现的.而且当你的对手是电脑时,是用 ...

  8. DP 算法: cutting a rod

    给定一个问题, 能够使用动态规划的方法解决的一个标志就是, 这个问题具有最优子结构(optimal substructure). 我们可以认为, 能够使用DP算法的问题首先能够分解为子问题. 而且我们 ...

  9. 动态规划算法python_动态规划——DP算法(Dynamic Programing)

    一.斐波那契数列(递归VS动态规划) 1.斐波那契数列--递归实现(python语言)--自顶向下 递归调用是非常耗费内存的,程序虽然简洁可是算法复杂度为O(2^n),当n很大时,程序运行很慢,甚至内 ...

最新文章

  1. 纪念计算机之父阿兰·图灵诞辰109周年
  2. 【 FPGA 】超声波测距小实验(一)
  3. poj1189 简单dp
  4. C语言试题十二之m个人的成绩存放在score数组中,请编写函数function,它的功能是:将低于平均分的人数作为函数值返回,将低于平均分的分数放在below所指定的数组中。
  5. Receiver type ‘X’ for instance message is a forward declaration
  6. 领导看了我写的关闭超时订单,让我出门左转!
  7. 13.卷1(套接字联网API)---守护进程和 inetd 超级服务器
  8. 软件工程--螺旋模型详解
  9. 本地文件怎么传到linux服务器,本地文件传到linux服务器
  10. 购买代购的产品算违法吗——看空姐代购被判刑有感
  11. chromecast协议_如何将Chromecast用作快速信息仪表板
  12. vue + element-ui 实现分页功能
  13. 一个男人的一生应该有几个女人?
  14. 跨境知道快讯:亚马逊推出“Buy with Prime”服务
  15. 汽车VIN码与二手车市场
  16. 微型计算机主板,四款ITX主板PK鉴赏
  17. 【线代】 线性方程组的解
  18. 2019 My excel
  19. Android系统触摸屏移植后出现小圆圈
  20. Bootstrap系列之卡片(Cards)

热门文章

  1. Ubuntu进入recover模式,修改系统文件
  2. VC2008程序的runtime环境
  3. 【2019暑假集训】06.28比赛总结
  4. matlab扩大虚拟内存
  5. 怀念啊我的青春(歌词)
  6. 大数据联合实验室落户青羊区
  7. 系统升级是为了修BUG、补漏洞?但也可能跟你想得完全不一样
  8. Audacity分析浊音清音爆破音的时域和频域波形图
  9. 点赞狂魔 (25 分) C语言
  10. javascript insertBefore( )