• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >编程问答 > 李白喝酒问题的算法

李白喝酒问题的算法

作者:佚名 字体:[增加 减小] 来源:互联网 时间:2017-06-07

佚名通过本文主要向大家介绍了李白喝酒问题,关于李白的问题,李白打酒问题,关于李白的诗的问题,李白喝酒等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
问题:李白喝酒问题的算法
描述:

“李白街上走,提壶去买酒,遇店加一倍,见花喝一斗”,途中,遇见5次店,见了10此花,壶中原有2斗酒,最后刚好喝完酒,要求最后遇见的是花,求可能的情况有多少种?希望大家分享一下思路,谢谢!
我的思路很混乱,觉得直接暴力枚举能解决,但是枚举所有的情况比较不现实,希望大家解答啊!


解决方案1:

暴力穷举很好做,不再说了
最后一次是见花的话,2经过说明经过14次变换之后值是1,
10次见花之后是0的话,初始是2斗酒,说明一共加了8斗酒
加酒最小值是1,最大是4(11114),
因为加酒是加倍方法,数列中相邻两个数倍差不能大于2倍,即11114这类被排除,可能加酒的数字在1-3的范围内,同样因为倍差原因,1后面只能是2(但是3后面可是是1)
因为初期值是2,第一次加酒只可能是1或者2斗
于是找有几个满足条件的数列就行

解决方案2:

简单的给一个非递归的python代码:

queue = [(2, 5, 10)]
total = 0
def iter():
    global queue
    while queue:
        i, queue = queue[0], queue[1:]
        yield i

for (left, dian, hua) in iter():
    if dian == 0:
        total += 1 if left == hua else 0
    else:
        if left > hua or left == 0 or hua ==0:
            continue
        queue.append((left*2, dian-1, hua))
        queue.append((left-1, dian, hua-1))

解决方案3:

"""
这是今年蓝桥杯java中的一道填空题,当时我还以为做对了,写了33
结果我忽略了最明显的判断条件,5次店和10次花,少了下面的 check1 函数
简直为自己的智商捉鸡,加了之后就是14了,
最近学python,现用python实现这题,跟大家分享
"""

count=0;
def check(t):
    sum = 2;
    for ch in t:
        if ch=='1':
            sum=sum*2;
        if ch=='0':
            sum=sum-1;
    return sum;
def check1(t):
    c = 0;
    for ch in t:
        if(ch=='1'):
            c+=1;
    if c==5:
        return True;
    return False;
def f(t):
    if(len(t)==15):
        if check(t)==0 and t[14:15]=='0' and check1(t):
            global count;
            count+=1;
            print(" ".join(t));
        return;
    f(t+'1');
    f(t+'0');
f('');
print(count);

解决方案4:

自己先粗略的写了一下,刚调试了一下,还是有点问题,已经被他折磨了两个小时了,先休息会儿等会儿再来debug!
结果debug了好久,也没我想的那么简单,也没人提示,今天又花了半个小时左右的时间,终于找到了问题的所在!

#include <iostream>

using namespace std;

int counting = 0;
int A[15];
int sum = 2;

int  collectArray()
{
int collect = 0;
for(int i =0;i<15;++i)
{
    if(A[i] == 0)
    collect++;
}
return collect;
}

void enumAll(int pos)
{
if(pos == 15)
{
    if(sum ==0 && A[14] == 1 )
    {
        counting++;
    }
}else{
    if(collectArray() <= 5)
    {
        A[pos] = 0;
        sum *= 2;
        enumAll(pos+1);
        A[pos] = 1;
        sum -= 1;
        enumAll(pos+1);
    }
    /*if(   <= 10)
    {
        A[pos] = 1;
        enuAll(pos+1);
        A[pos] = 0;
        enumAll(pos+1);
    }*/
    }
}

int main()
{
    for(int i =0;i<15;++i)
    {
        A[i] = -1;
    }
    enumAll(0);
    cout << counting;
    return 0;
}

更新版本,已通过测试:

#include <iostream>

using namespace std;

int counting = 0;
int A[15];
int sum = 2;

int  collectArray()
{
    int collect = 0;
    for(int i =0;i<15;++i)
    {
        if(A[i] == 0)
        collect++;
    }
    return collect;
}

void enumAll(int pos,int sonSum)
//直接采用枚举方法,A[]中每个元素不是0就是1
//若采用if判断则会产生15层嵌套
//因此采用树的深度优先遍历
//建议我使用栈来操作
//问题已经被发现,我TMD就是个天才,sum是个全局变量,在递归的时候,已经变不回来    //了!
{
    if(pos == 15)
    {
        if(sonSum == 0 && A[14] == 1 &&  collectArray() == 5)
        {
            counting++;
            for(int i =0;i<15;++i)
            cout << A[i] << "  ";
            cout << endl;
            return;
        }
    }else{
        //if(collectArray() <= 5)
            A[pos] = 0;
            sonSum  *= 2;
            enumAll(pos+1,sonSum);
            A[pos] = 1;
            sonSum = sonSum / 2;
            sonSum -= 1;
            enumAll(pos+1,sonSum);
            return;
    //}
    /*if(   <= 10)
    {
        A[pos] = 1;
        enuAll(pos+1);
        A[pos] = 0;
        enumAll(pos+1);
    }*/
    }
}

int main()
{
    for(int i =0;i<15;++i)
    {
        A[i] = -1;
    }
    enumAll(0,sum);
    cout << counting << endl;
    return 0;
}

解决方案5:

给你一段更容易理解的代码,用递归做的:

#include <iostream>
using namespace std;
int count = 0;
int path[ 20 ];

void dfs( int m, int n, int r, int c )//m 遇店的次数,n 遇花的次数
{
    if( m < 0 || n < 0 || r < 0 )
        return ;
    if( m ==0 && n == 0 && r == 1 )
    {
        path[ c ] = '\0';
        cout << path << endl;
        count++;
    }
    path[ c ] = 'a';
    dfs( m -1 , n, r * 2, c + 1 ); 
    path[ c ] = 'b';
    dfs( m, n - 1, r - 1 , c + 1 ); 
}

int main() 
{
    dfs( 5, 9, 2, 0 );
    cout << count << endl;
    return 0;
}

解决方案6:

让我来个haskell递归版的

drink :: Int -> Int -> Int -> Int
drink 1 0 1 = 1
drink wine inn flower
 | wine < 0 = 0
 | inn < 0 = 0
 | flower < 0 = 0
 | otherwise = drink (wine-1) inn (flower-1) + (drink (wine*2) (inn-1) flower)
*Main> drink 2 5 10
14

解决方案7:

自己写不来,让某大神写的枚举代码:

int main()
{
    int cnt=0;
    for (int i=0; i<1<<15; i++)
    {
        int k=2;
        int n=0;
        int x=i;
        int flag=1;
        for (int j=1; j<=15; j++)
        {
            if (x&1)
                k*=2;
            else
                k--;
            if (k==0&&x)
            {
                flag=0;
                break;
            }
            n+=x&1;
            x>>=1;
        }
        if ( n !=5 || (i & (1<<14)) || !flag || k != 0)
            continue;
        cnt++;
    }
    cout<<cnt<<endl;
    return 0;
}

解决方案8:

额...代码如下(python版):

def w(f,d,h): return (1 if f==h else 0) if d==0 else (0 if f*h==0 or f>h else w(f*2, d-1, h)+w(f-1, d, h-1))

执行w(2,5,10) 结果14

解决方案9:

我想一个穷举的思路吧~其实不用很多步骤的~
首先要递归
开始2斗,5酒店,10花;
楼上都完整了...
提供优化条件吧
如果酒店完了,并且斗和花不等,就能退出;
如果斗大于花也能退出;
斗已经是0直接退出;
花是零,但没到15步也退出;

解决方案10:

哎……大家都各贴各的代码,也不说说重要的优化思路

翻了一下还几乎没在答案里找到靠谱的优化思路解说,如果这是我在面试的话这里的答案几乎没人到我心理预估60分……

为了方便描述,定义一下李白(x, y, z) => 还有x次花,y次店,z斗酒的答案

先说不重要的吧,剪枝条件是可以比各位的答案更激进一些的,比如z > x的时候玩命喝也喝不完了可以剪,同理z * (2 ^ y) < x的时候即使马上狂打酒也不够喝了可以剪。


正文分隔线


这个问题最明显的特征就是有规模,并且大规模版本的答案是和小规模版本的答案密切相关的,也就是已知李白(x, y, z),我们马上就能知道李白(x+1, y, z+1) 或者李白(x, y+1, 2z)的答案。
不知道到这里有没有人能想起菲波纳契数列和对应的经典计算机算法动态规划。动态规划是非常经典的空间换时间的算法,可以把这类问题 最笨拙的暴力递归算法瞬间改造成性能相当良好的算法。

实际上,不用动态规划的话,这类问题的递归算法会很快随着规模的增长而崩溃,具体O多少还给算法老师了,反正肯定是逆天指数级的。动态规划以后基本可以降到多项式级别

最后给出我的实现,嗯,JS的

http://jsfiddle.net/e3Ns4/

_.memoize(fn, hasher)是underscore里的一个helper,作用是生成一个新的

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 李白喝酒问题的算法

相关文章

  • 2017-06-07 (python)怎么对dataframe中筛选过的数据进行计算
  • 2017-06-07 flask(python)Flask动态导航条
  • 2017-06-07 谁有jbpm-starters-kit-312zip?在JBOSS官网上找不到,急~有的人请加我QQ724247860
  • 2017-06-07 使用NFS文件夹作为mysqldatadir无法启动mysql的问题?
  • 2017-06-07 为什么在java中用反射要加异常处理
  • 2017-06-07 使用镜像存储,在回源时源地址里的参数被过滤了。
  • 2017-06-07 djangodjango前端模板
  • 2017-06-07 (python)爬虫爬取html5页面上的视频是怎样的一种处理方式的
  • 2017-06-07 求一则算法(python)
  • 2017-06-07 大家如何配置系统的dir_color的?

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 用户把视屏发送给微信公众账号怎么转到七牛云
    • 下载哪个版本开始自学python?
    • pythonSMTP連接總是有錯誤怎麼解決??
    • pythonjson字符串打印中文的问题(unicode)
    • Drools407的例子在ecllipse341中编译存在错误
    • 分享一个jboss上richface组件的问题的解决方案,顺带求根本原因
    • (python)httplibget请求报错httplibBadStatusLine:''
    • rubygems更换淘宝source的时候certificateverifyfailed
    • pythondecode'utf-8'出现错误:invalidstartbyte?
    • 我对于你你对于我对于在Python中使用元类实现单例模式的困惑?

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有