李白打酒解题报告(dfs)

问题描述:

话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb就是合理的次序。

像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

解答:本题是一道通过搜索求解空间的题,通过dfs算法,递归的找出所有可能,若是答案则ans++,本题需要注意的是最后一次要求必须是花,

所以在递归的时候要告诉下一次本次是花还是酒。

#include <stdio.h>
#include <math.h>
int ans;//全局变量记录成功次数
void dfs(int alco,int store,int flower, int pre)//变量分别代表:当前酒多少,还可以遇到店几次,还可以遇到花几次,上一次遇到的花还是店(0代表花,1代表店)
{
        if(store == 0 && flower == 0 )//若遇店次数没了,遇花次数也没了,则可能是解
        {
            if(pre == 0 && alco == 0)//若上一次即最后一次遇到的是花,且酒也没了,这时候可以确定是答案了
                ans++;
            return ;
        }
        if(store > 0)
        {
            dfs(alco*2,store-1,flower,1); //假设本次遇到店,递归的求以后的答案
        }
        if(alco > 0 && flower > 0)
        {
            dfs(alco-1,store,flower-1,0); //假设本次遇到花,递归的求以后的答案
        }
        return ;
}
int main()
{
        ans = 0;
        dfs(2,5,10,2); //初始有酒2,花5,店10
        printf("%d\n",ans);
        return 0;
}

2.通过位运算

#include <iostream>

using namespace std;

bool CheckNum(int num)  // 数字满足5个1,即5个店
{
    int bcount = 0;
    for(int i = 0; i < 15; i++) // 最后遇到花,所以不用判断最开始位置
    {
        if(num & 0x1 == 1) bcount++;  // 只取最后一位并判断
        num = num >> 1;
    }
    if(5 == bcount) return true;
    else return false;
}

void BinaryOutput(int num) // 数字按照2进制输出,以便验证
{
    for(int i = 0; i < 16; i++)
    {
        if(i <= 1) cout<<"0"; // 前两位不用判断,直接是0
        else
        {
            int inum = (num >> (15 - i));
            inum = inum & 0x1;       // 位操作后与操作取第i位
            if(inum == 1) cout<<"1";
            else cout<<"0";
        }
        if((i + 1)%4 == 0 && i != 15) cout<<",";  // 输出4位后分隔
    }
    cout<<endl;
    return;
}

bool CheckWine(int num, int wine) // 从后向前判断数字的2进制位,判断酒的数目
{
    int i = 0;
    while(i <= 14 && wine >= 0) // 防止wine < 0 情况出现
    {
        int inum = num & 0x1;   // 取最后一位,即当前遇到的是花还是店
        if(inum == 1) wine = wine << 1;  // 右移一位,即X2
        else wine--;
        num = num >> 1;   //数字当前位判断完成,右移,判断下一个最后位

        i++;
    }
    if(0 == wine && i > 14) return true;
    else return false;
}

int main()
{
    // 0 表示遇花,1 表示遇店, 从后向前表示遇的次数
    int iMax = 0x7C00;  // 最后5个连续是店是最大值(0011,1110,0000,0000)
    int iMin = 0x1F; // 前5个连续是店是最小值(0000,0000,0001,1111)
    int iCount = 0; // 符合的数字计数
    cout<<"可能的情况(顺序从后往前,1表示店,0表示花): "<<endl;
    for(int i = iMin; i <= iMax; i++)
    {
        if(CheckNum(i) && CheckWine(i, 2))
        {
            cout<<++iCount<<"\t";
            BinaryOutput(i);
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41282102/article/details/81483605
今日推荐