XTU OJ 1168 Alice and Bob (二维dp)

本文介绍了一种经典的石头游戏问题,通过动态规划求解Alice和Bob合作取石的最少步骤。采用二维DP方法,详细解析了状态转移方程,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Alice and Bob

Accepted : 98 Submit : 324
Time Limit : 1000 MS Memory Limit : 65536 KB

Problem Description

Alice and Bob always love to play games, so does this time. 
It is their favorite stone-taken game. 
However, this time they does not compete but co-operate to finish this task. 
Suppose there is a stack of n stones. 
Each turn, 
Alice can only take away stones in number pow of 2, say 1, 2, 4, 8, 16, ... 
Bob can only take away stones in number pow of 3, say 1, 3, 9, 27, 81, ... 
They takes stones alternately, and lady first.
Notice in each turn, Alice/Bob have to take away at least one stone, unless the stack is empty. 
Now, the question is, what is the least number of operation for taking away all the stones.

Input

Multiple test cases. First line, there is an integer T ( 1 ≤ T ≤ 20 ), indicating the number of test cases. 
For each test case, there is a number n ( 1 ≤ n ≤ 10000 ), occupying a line, indicating the total number of the stones.

Ouput

For each test case, output a line. It is an integer number k, indicating the least number of operation in need to finish the task.

Sample Input
5
1
2
3
4
5
Sample Output
1
1
2
1
2

Source

XTU OnlineJudge

去年看到这道题目的时候对动态规划没有一点思路,不知道该怎么往那方面想,对动态规划有种畏惧的感觉。重新来做这道题目,往那方面想还是得不出递推方程式啊,动态规划还是得多练,还需要有一定的灵感;看了一下别人的思路,终于看懂了,http://blog.youkuaiyun.com/libin56842/article/details/26287101  用自己的风格写了一遍;

这里用的是二维dp,用dp[i][0]:alice 取i颗石子所用的最小步数(alice是先手);

                                     dp[i][1]:bob 取i颗石子所用的最小步数;

alice先取石子,如果alice一次没有取完,bob就接着取,我们要得到的是取完所用的最小步数,所以我们可以得到状态关系式;

min(dp[i][0],dp[i-j][1]+1); j就是Alice取走的颗数,bob接着取次数就要加1;

下面是代码:

#include <cstdio>
#include <cstring>
#define min(a,b) a<b?a:b
const int maxn=10005;
const int Max=0x3f3f3f3f;
int dp[maxn][2];
int main()
{
    int t,n,i,j;
    dp[0][0] = dp[0][1] = 0;
    dp[1][0]=dp[1][1]=dp[2][0]=1;//一次可以取完
    dp[2][1]=2;//bob要取两次
    for(i=3;i<maxn;i++)//这里我们就要从3开始了
    {
        dp[i][0]=dp[i][1]=Max;//初始值赋为最大值
        for(j=1;j<=i;j*=2)//alice每次取的是2的j次
            dp[i][0]=min(dp[i][0],dp[i-j][1]+1);//比较直接的最小值
        for(j=1;j<=i;j*=3)//bob取的
            dp[i][1]=min(dp[i][1],dp[i-j][0]+1);
    }
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        printf("%d\n",dp[n][0]);//这里按的是alice为先手算的
    }
    return 0;
}


### XTUOJ 平台上的二分指针问题及解决方法 #### 什么是二分指针算法? 二分指针是一种高效的搜索技术,通常用于有序数组中快速定位目标值。该算法通过反复将搜索区间减半来缩小查找范围,从而显著提高效率[^1]。 #### 解决方案概述 对于给定的数据集,在处理过程中遇到不能整除的情况时确实需要注意区分奇数和偶数元素分别存储于不同容器内以便后续计算其均值并继续迭代直至满足终止条件为止。然而这种方法可能会带来较高的时间复杂度因此建议优化策略如下: - **预处理阶段**:读取输入数据的同时完成初步分类工作即将所有数值依据奇偶性质分配至相应列表; - **核心逻辑设计**: - 对每一对相邻项执行平均化运算之前先确认它们是否同属一类(即均为奇数或偶数),只有当两者皆为同一类别成员才允许进行下一步骤; - 计算所得新值应追加到临时缓冲区而非立即覆盖原位置以防破坏原有结构影响后续判断准确性; - **循环控制机制构建**:设置计数器监控剩余待处理单元数量一旦降至单个则停止整个流程输出最终结果。 ```python def process_elements(elements): odd_numbers = [] even_numbers = [] # 将原始序列中的元素按奇偶性分离 for num in elements: if num % 2 == 0: even_numbers.append(num) else: odd_numbers.append(num) while len(odd_numbers) + len(even_numbers) > 1: new_odd = [] new_even = [] # 处理奇数列表 i = 0 while i < len(odd_numbers)-1: avg = (odd_numbers[i] + odd_numbers[i+1]) // 2 new_odd.append(avg) i += 2 # 如果有剩余的最后一个奇数,则保留它 if i < len(odd_numbers): new_odd.append(odd_numbers[-1]) # 类似地处理偶数列表... # 更新旧列表 odd_numbers, even_numbers = new_odd, new_even result = odd_numbers or even_numbers return result[0] if result else None ``` 此段代码展示了如何基于上述原则实现一个简化版的功能模块,实际应用中可能还需要考虑更多边界情况以及性能调优措施以适应更广泛的需求场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值