洛谷P1328 生活大爆炸版石头剪刀布

本文介绍洛谷P1328题目,一种升级版的石头剪刀布游戏,增加了斯波克和蜥蜴人手势,通过分析周期性的出拳规律,统计N次猜拳后两玩家的得分。使用C语言实现游戏逻辑,根据不同的手势判断胜负。

洛谷P1328 生活大爆炸版石头剪刀布

题目描述

石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头。如果两个人出拳一 样,则不分胜负。在《生活大爆炸》第二季第8集中出现了一种石头剪刀布的升级版游戏。

升级版游戏在传统的石头剪刀布游戏的基础上,增加了两个新手势:

斯波克:《星际迷航》主角之一。

蜥蜴人:《星际迷航》中的反面角色。

这五种手势的胜负关系如表一所示,表中列出的是甲对乙的游戏结果。

现在,小 A小 B尝试玩这种升级版的猜拳游戏。已知他们的出拳都是有周期性规律的,但周期长度不一定相等。例如:如果小A以“石头-布-石头-剪刀-蜥蜴人-斯波克”长度为 6 的周期出拳,那么他的出拳序列就是“石头-布-石头-剪刀-蜥蜴人-斯波克-石头-布-石头-剪刀-蜥蜴人-斯波克-......”,而如果小B以“剪刀-石头-布-斯波克-蜥蜴人”长度为 555 的周期出拳,那么他出拳的序列就是“剪刀-石头-布-斯波克-蜥蜴人-剪刀-石头-布-斯波克-蜥蜴人-......”

已知小 A小 B 一共进行 N次猜拳。每一次赢的人得 1 分,输的得 0 分;平局两人都得 0 分。现请你统计 N 次猜拳结束之后两人的得分。

输入输出格式

输入格式:

 

第一行包含三个整数:N,NA,NB分别表示共进行 N 次猜拳、小 A出拳的周期长度,小 B 出拳的周期长度。数与数之间以一个空格分隔。

第二行包含 NA​ 个整数,表示小 A出拳的规律,第三行包含 NB​ 个整数,表示小 B 出拳的规律。其中,0 表示“剪刀”,1 表示“石头”,2 表示“布”,3表示“蜥蜴人”,4表示“斯波克”。数与数之间以一个空格分隔。

输出格式:

 

输出一行,包含两个整数,以一个空格分隔,分别表示小 A小 B的得分。

 

输入输出样例

输入样例#1: 

10 5 6
0 1 2 3 4
0 3 4 2 1 0

输出样例#1: 

6 2

输入样例#2: 

9 5 5
0 1 2 3 4
1 0 3 2 4

输出样例#2: 

4 4

在题目中已经说明了双方出什么时的输赢情况,在这里为了表示清楚,我直接将表示的输赢情况表示出来
a出0时,b出2,3,a赢,b出1,4,b赢;
a出1时,b出0,3,a赢,b出2,4,b赢;
a出2时,b出1,4,a赢,b出0,3,b赢;
a出3时,b出2,4,a赢,b出0,1,b赢;
a出4时,b出0,1,a赢,b出2,3,b赢;
照着这样输赢判断用循环表示即可

#include<stdio.h>
int main()
{
	int n, a, b;
	
	scanf("%d %d %d", &n, &a, &b);
	
	int x[1005], y[1005];
	
	for(int i = 0; i < a; i++)
		
		scanf("%d", &x[i]);
	
	for(int i = 0; i < b; i++)
	
		scanf("%d", &y[i]);
	
	int x1 = 0, y1 = 0;
	
	int numa = 0, numb = 0;
	
	for(int i = 0;i < n; i++)
	{
		if(x[x1] == 0)
		{
			
			if(y[y1] == 2 || y[y1] == 3)
				
				numa++;
			
			if(y[y1] == 1 || y[y1] == 4)
				
				numb++;
		}
		
		if(x[x1] == 1)
		{
			
			if(y[y1] == 0 || y[y1] == 3)
				
				numa++;
			
			if(y[y1] == 2 || y[y1] == 4)
			
				numb++;
		}
		
		if(x[x1] == 2)
		{
			
			if(y[y1] == 1 || y[y1] == 4)
			
				numa++;
			
			if(y[y1] == 0 || y[y1] == 3)
			
				numb++;
		}
		
		if(x[x1] == 3)
		{
			
			if(y[y1] == 2 || y[y1] == 4)
			
				numa++;
			
			if(y[y1] == 0 || y[y1] == 1)
			
				numb++;
		}
		
		if(x[x1] == 4)
		{
			
			if(y[y1] == 0 || y[y1] == 1)
			
				numa++;
			
			if(y[y1] == 2 || y[y1] == 3)
			
				numb++;
		}
		
		x1++;
		
		y1++;
		
		if(x1 == a)
		
			x1=0;
		
		if(y1 == b)
		
			y1 = 0;
	}
	
	printf("%d %d", numa, numb);
 } 

 

 

 

 

<think>嗯,用户问的是洛谷P1122最大子树的解题思路,涉及到数据结构、树形DP算法实现。首先,我需要回忆一下这个题目的具体要求。题目要求通过修剪得到最大的美丽指数,也就是在树中选择一个连通的子树,使得节点值的最大。这应该是一个典型的树形DP问题。 根据引用[1],树形DP通常是在树上做动态规划,递归处理子树的信息。所以基本步骤应该是把树转为有根树,然后DFS遍历,从叶子节点向上汇总信息。这里的关键是设计DP状态转移方程。 引用[2]提到这道题需要将花卉结构抽象为树,用树形DP动态规划。具体步骤包括构建树的数据结构,然后DFS计算每个节点的最大子树。我需要确定DP状态的定义,比如dp[u]表示以u为根的子树中的最大,包括选择u的情况。 然后考虑转移方程。对于每个节点u,遍历其子节点v,如果v的dp值大于0,就加上,否则不加。这样dp[u] = value[u] + sum(max(dp[v], 0))。这样就能保证每个节点的贡献是正的,否则不选该子树。 数据结构方面,通常用邻接表来存储树的结构。每个节点保存其子节点的列表。在代码实现时,需要注意避免重复访问父节点,所以DFS的时候需要记录父节点。 然后需要考虑初始化,每个节点的初始dp值就是它自身的值。然后递归处理所有子节点,更新dp[u]的值。 另外,题目中的树可能有多个分支,所以最终的答案不一定是根节点的dp值,而是所有节点dp值中的最大值。因此,在遍历过程中需要维护一个全局最大值。 引用[3]中的代码实现部分可能有帮助,比如如何处理DFS状态转移。例如,在遍历子节点时,计算它们的dp值,然后决定是否加上。 还有,边界条件处理,比如叶子节点,它的子节点处理完后,dp值就是它本身的值加上子节点中正的贡献,但实际上叶子节点没有子节点,所以直接返回自己的值。 测试样例可能需要考虑有正有负的情况,比如某个子树的为负,这时候应该剪掉,不选择该子树。 总结步骤:1. 构建树的邻接表;2. DFS遍历,计算每个节点的dp值;3. 在过程中记录最大值;4. 输出最大值。 现在需要把这些步骤详细地解释出来,确保用户能理解每个部分的作用。例如,邻接表如何构建,如何避免访问父节点,DP状态转移的逻辑,以及如何维护全局最大值。 可能还需要注意一些细节,比如节点编号是否从1开始,输入的处理方式,以及如何处理较大的数据量,但题目中的具体数据规模可能根据引用[4]中的说明,绝对值不超过2147483647,所以用int应该足够,但代码中可能需要用长整型以防万一。 最后,确保代码示例正确,用Python的话可能需要递归实现DFS,但需要注意Python的递归深度限制,不过题目中的数据范围可能不会太大。或者用户可能希望用其他语言,但根据用户提供的示例,Python代码是可行的。</think>### 洛谷 P1122 最大子树 解题思路 #### 问题分析 题目要求在一棵树中选择一个**连通子树**,使得该子树所有节点的“美丽指数”之最大。这本质上是树形动态规划(Tree DP)的典型问题,通过状态转移计算每个子树的最优解。 #### 核心思路 1. **状态定义** 定义 $dp[u]$ 表示以节点 $u$ 为根的子树中,**必须包含 $u$** 的最大美丽指数- 若子节点的 $dp[v] > 0$,则选择该子树(累加收益) - 若 $dp[v] \leq 0$,则舍弃该子树(避免损失) 2. **转移方程** $$dp[u] = \text{value}[u] + \sum_{\text{子节点 }v} \max(dp[v], 0)$$ 3. **全局最大值** 最终的答案并非直接取根节点的 $dp$ 值,而是所有节点的 $dp[u]$ 中的最大值,因为最优解可能存在于某棵子树中。 #### 数据结构与算法实现 1. **树的存储** 使用**邻接表**存储树结构,例如: ```python tree = [[] for _ in range(n+1)] # 节点编号从1开始 for _ in range(n-1): u, v = map(int, input().split()) tree[u].append(v) tree[v].append(u) ``` 2. **DFS递归遍历** - **递归终止条件**:叶子节点(无子节点) - **关键操作**:遍历子节点时跳过父节点,避免回路 ```python def dfs(u, parent): dp[u] = value[u] # 初始化dp[u]为节点自身值 for v in tree[u]: if v == parent: # 避免回溯父节点 continue dfs(v, u) # 递归处理子节点 if dp[v] > 0: # 仅当子节点贡献为正时累加 dp[u] += dp[v] nonlocal max_sum max_sum = max(max_sum, dp[u]) # 更新全局最大值 ``` 3. **初始化与调用** ```python value = [0] + list(map(int, input().split())) # 假设输入为节点1~n的值 dp = [0] * (n+1) max_sum = -float('inf') dfs(1, -1) # 假设根节点为1,父节点标记为-1 print(max_sum) ``` #### 复杂度分析 - **时间复杂度**:$O(n)$,每个节点仅访问一次 - **空间复杂度**:$O(n)$,存储树DP数组 #### 示例解释 假设输入树结构如下(节点值为 $[1, 2, 3, 4, 5]$): ``` 1 ├─2 └─3 ├─4 └─5 ``` - 节点3的 $dp$ 计算:$3 + \max(4, 0) + \max(5, 0) = 12$ - 全局最大值可能出现在以3为根的子树中[^2][^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值