当前位置: 首页 > news >正文

【算法学习笔记】27.动态规划 解题报告 SJTU OJ 1254 传手绢

Description

活动的时候,老师经常带着同学们一起做游戏。这次,老师带着同学们一起传手绢。

游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着手绢,当老师吹哨子时开始传,每个同学可以把手绢传给自己左右的两个同学中的一个(左右任意),当老师在此吹哨子时,游戏停止,此时,拿着手绢的那个同学要给大家表演一个节目。

abc提出一个有趣的问题:有多少种不同的传手绢方法可以使得从abc手里开始传的手绢,传了m次以后,又回到abc手里。两种传手绢方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接手绢顺序组成的序列是不同的。比如有三个同学1号、2号、3号,并假设abc为1号,手绢传了3次回到abc手里的方式有1->2->3->1和1->3->2->1,共2种。

Input Format

共一行,有两个用空格隔开的整数n,m(3<=n<=30,1<=m<=30)。

Output Foramt

共一行,有一个整数,表示符合题意的方法数。

Sample Input

3 3 

Sample Output

2

Hint

40%的数据满足:3<=n<=30,1<=m<=20 100%的数据满足:3<=n<=30,1<=m<=30

 

此问题很容易让人联想到邻接矩阵乘法含义。wiki了一下,这类问题叫做”传球问题“  

证明在这里  矩阵乘法确实好理解 但是实际应用还是稍微复杂,

这里先用一个递归方案来把这个问题进行解析。

注意到一个人传球,只能传左一位和右一位,根据这个突破点就可以写成递归函数。

/*分治法
返回 一共n个人 还剩m次传球机会 最终传到第k个人手里的路线数
k是当前拿球的人的编号 1号是最开始拿球的人
*/
int passGame(int k,int n, int m){
    if(m==0)
        //若还剩0次传球机会 整好到了原处 那就返回1 表示原来的路线是对的 否则是0
        return (k==1) ? 1 : 0;
    m--;//开始传球了 所以要减少一次传球机会
    //向+1传的话
    int ans1 = passGame((k==n ? 1 : k+1 ),n,m);
    //向-1传的话
    int ans2 = passGame((k==1 ? n : k-1 ),n,m);

    return ans1+ans2;

}    
分治法

然后调用passGame(1,n,m)即可

会超时,这种分治法的解决方案是从顶至底的。它会有很多重复的计算,所以我们就会想到和分治法路线相反的动态规划。

动态规划的一个核心思想就是将重复子问题提前计算,从而减少计算量。这也就意味着它必须从底向上计算。

在这个背景下,我们可能直觉想到的是设置一个dp[n][m] 其中d[n][m]表示n个人 传m次 回到原点的方案数,

然后想办法建立起 d[n][m]和d[n][m-1]的关系 或者和 d[n-1][m]的关系 或者和d[n-1][m-1]的关系,从而实现把这个问题分成若干个子问题来进行DP。

但是发现找到他们之间的关系,非常困难。

我们试着换一个思路,由分治法的思维,我们知道了一个事情就是 还剩s次传球机会时,球传到第k个人手里的路线数 = 还剩s-1次传球机会时,球传到第k+1个人手里的路线数 + 还剩s-1次传球机会,球传到第k-1个人手里的路线数

PS s-1的原因是最后还要耗费一次传球机会来把球传到k手里 k+1 k-1 只是简单的表示k的左右

那么我们就可以考虑构造一个dp[][]来存储还剩m次机会 传到第k个人手里的路线数目 这个dp方案就是把分治法给颠倒了而已 思路是完全一模一样的

 

//动态规划算法
int dp[35][35]={0};

/*dp[i][j]表示 传i次球 传到第j个人的路线的个数
起始点和终止点都是为1号人
*/
int dp_game(int n,int m){
    dp[0][1]=1;//传0次 传到1号人手中 路线只有一个
    //开始找状态转移方程 
    /*其实想法很简单 就是想d[i][j]是从哪些状态过来的 
        d[i][j]应该是d[i-1][j-1]和d[i-1][j+1]来的 因为j只能收到j-1和j+1的球
        而每次传球恰好i+1
    传0次球 只有1号人才能接到球 其他人都是0 不用算

    */
    for (int i = 1; i <= m; ++i){
        for (int j=1; j <= n; ++j){
            dp[i][j] = dp[i-1][j==1 ? n: j-1 ] + dp[i-1][j==n? 1:j+1];
        }
    }
    return dp[m][1];
}
动态规划

 

转载于:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1254.html

相关文章:

  • Android 通过代码设置radiobutton不同方位图标的两种方法
  • 【嵌入式开发板】大家都在玩儿的4412开发板
  • Hadoop2源码分析-MapReduce篇
  • CentOS 7安装后配置笔记
  • Linux常用的基本命令11
  • 40策略时独立需求的冲减
  • js里正则表达式详解
  • mysql表的导入导出
  • autocomplete实现联想输入,自动补全
  • Android+struts2+JSON方式的手机开发(Login)
  • AOP (面向切面编程)
  • CSS背景属性Background详解
  • 第十六条:组合优先于继承
  • 安装readline-6.2.4.1
  • mysql锁机制详解及死锁处理方式
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • cookie和session
  • IP路由与转发
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • MaxCompute访问TableStore(OTS) 数据
  • miaov-React 最佳入门
  • MySQL几个简单SQL的优化
  • Object.assign方法不能实现深复制
  • RxJS: 简单入门
  • select2 取值 遍历 设置默认值
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 前端路由实现-history
  • 学习Vue.js的五个小例子
  • 你对linux中grep命令知道多少?
  • 【云吞铺子】性能抖动剖析(二)
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • ​比特币大跌的 2 个原因
  • # 达梦数据库知识点
  • #### go map 底层结构 ####
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • (6)添加vue-cookie
  • (9)STL算法之逆转旋转
  • (C语言)字符分类函数
  • (poj1.2.1)1970(筛选法模拟)
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (编译到47%失败)to be deleted
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (论文阅读40-45)图像描述1
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转)JAVA中的堆栈
  • (转)Linux下编译安装log4cxx
  • (转)四层和七层负载均衡的区别
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件