2608: 石子

石子游戏胜负判断算法

 2608: 石子


ResultTIME LimitMEMORY LimitRun TimesAC TimesJUDGE
1s131072K469116Standard

Xiao Tang和Xiao Jiang非常喜欢玩一种有趣的小游戏: 有N个石子,两人轮流从中取出1个, 3个或4个石子,当石子被取空时,游戏结束。最后一个取石子的人获胜, 第一次总是Xiao Tang取. 当然,他们俩都足够聪明,总会采取最优的策略。

Input

每行会有一个正整数N(N<=100000), 代表石子的个数, N=0 代表输入结束

Output

输出获胜人的名字。

Sample Input

1
2
0

Sample Output

Xiao Tang
Xiao Jiang
如果一个节点的所有后续节点都是必胜态,该节点为必败态,否则该节点为必胜态。也即是说,只要有一个后续节点是必败态,该节点就是必胜态。
最后一天为必败态,倒数第一天为必胜态,从后往前推。
#include<iostream>
#include<cstdio>
using namespace std;
int a[100010]={0,1,0,1,1};
int main()
{
    for(int i=5;i<100010;i++)
    {
        if(a[i-1]&&a[i-3]&&a[i-4]) a[i]=0;
        else a[i]=1;
    }
    int n;
    while(scanf("%d",&n)==1&&n)
    {
        if(a[n]) printf("Xiao Tang/n");
        else printf("Xiao Jiang/n");
    }
    return 0;
}
### 石子合并问题的解决方案 石子合并问题是经典的动态规划问题之一,主要涉及如何通过合理的策略将多堆石子逐步合并为一堆,使得整个过程中满足特定条件下的代价最小化或最大化。 #### 1. 问题分析 对于线性排列的石子合并问题[^2],假设存在 `n` 堆石子,每堆石子的质量分别为 `w[1], w[2], ..., w[n]`。目标是找到一种合并方式,使得总的合并代价达到最小或者最大。 定义状态变量 `dp[i][j]` 表示从第 `i` 堆到第 `j` 堆石子合并后的最优解(可以是最小代价或最大代价),则可以通过如下状态转移方程计算: - **状态转移方程**: \[ dp[i][j] = \min_{k=i}^{j-1}(dp[i][k] + dp[k+1][j] + sum(i, j)) \quad (\text{最小代价}) \] 或者, \[ dp[i][j] = \max_{k=i}^{j-1}(dp[i][k] + dp[k+1][j] + sum(i, j)) \quad (\text{最大代价}) \] 其中,`sum(i, j)` 是从第 `i` 到第 `j` 堆石子的总重量,可通过预处理前缀和快速计算得到。 #### 2. 实现细节 为了提高效率,在实现中通常会先计算并存储所有的前缀和数组 `prefix_sum[]`,以便能够 O(1) 时间复杂度查询任意区间的石子总重。 以下是基于 C++ 的具体代码实现: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int stoneMergeMin(vector<int>& stones) { int n = stones.size(); vector<vector<int>> dp(n, vector<int>(n, 0)); vector<int> prefixSum(n + 1, 0); // 计算前缀和 for (int i = 1; i <= n; ++i) { prefixSum[i] = prefixSum[i - 1] + stones[i - 1]; } // 初始化长度为1的情况 for (int l = 2; l <= n; ++l) { // 枚举区间长度 for (int i = 0; i + l - 1 < n; ++i) { // 枚举起始位置 int j = i + l - 1; dp[i][j] = INT32_MAX; for (int k = i; k < j; ++k) { // 枚举分割点 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + prefixSum[j + 1] - prefixSum[i]); } } } return dp[0][n - 1]; // 返回全局最优解 } // 测试函数 void testStoneMerge() { vector<int> stones = {4, 5, 9}; cout << "Minimum cost to merge all piles: " << stoneMergeMin(stones) << endl; } ``` 上述代码实现了寻找最小合并成本的功能。如果需要求解最大合并成本,则只需修改状态转移中的 `min` 函数为 `max` 即可。 #### 3. 圆形石子合并扩展 当石子呈环状分布时,需将其转化为线性问题再加以解决。常用的方法是对原序列复制一份拼接起来形成双倍长度的新序列,并按照前述方法分别考虑各可能断开的位置作为起点进行计算[^3]。 --- ### 结论 综上所述,利用动态规划的思想可以有效解决石子合并这一类优化问题。核心在于合理地划分阶段以及构建合适的状态转移关系,从而保证能够在多项式时间内得出精确的结果。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值