Broken Necklace

本文介绍了一个USACO竞赛中的珠子收集问题,通过简单的模拟算法解决如何从一串可变色的珠子项链中收集最多数量的珠子。文章详细解释了算法思路并提供了C++实现代码。

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

题目:http://ace.delos.com/usacoprob2?S=beads&a=58XzirPinKZ


题目大意:有一串项链  可以从每两个珠子中间剪断 然后从左右两边收集珠子 白色的可以代表任何颜色 遇到不一样颜色的珠子则停止


简要分析:简单模拟 注意当r<0 以及 l>=N的情况的边界处理  用一个status数字记录每个珠子是否被摘走


#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<vector> #include<map> using namespace std; const int N=2005; const int inf=0x3f3f3f3f; int ans=-1; string a; int f(int x){ int s=0,i; char a1=a[x],b1=a[x+1]; for(i=x;;i--){ if(a[i]==a1||a[i]=='w') s++; else break; } for(i=x+1;;i++){ if(a[i]==b1||a[i]=='w') s++; else break; } return s; } int main() { int n,len,m,i,j,k,x,y; cin>>len>>a; a=a+a+a; for(i=len;i<len*2;i++){ if(a[i]==a[i+1]) continue; if(a[i]=='w'){ a[i]='r'; ans=max(ans,f(i)); a[i]='b'; ans=max(ans,f(i)); a[i]='w'; } ans=max(ans,f(i)); } ans=min(ans,len); if(ans==-1) ans=len; printf("%d",ans); return 0; } P1203 [USACO1.1]坏掉的项链Broken Necklace 题目描述 你有一条由 nn 个红色的,白色的,或蓝色的珠子组成的项链,珠子是随意安排的。 这里是 n=29n=29 的两个例子: 第一和第二个珠子在图片中已经被作记号。 图片 A 中的项链可以用下面的字符串表示: brbrrrbbbrrrrrbrrbbrbbbbrrrrb 假如你要在一些点打破项链,展开成一条直线,然后从一端开始收集同颜色的珠子直到你遇到一个不同的颜色珠子,在另一端做同样的事(颜色可能与在这之前收集的不同)。 确定应该在哪里打破项链来收集到最大数目的珠子。 例如,在图片 A 中的项链中,在珠子 99 和珠子 1010 或珠子 2424 和珠子 2525 之间打断项链可以收集到 88 个珠子。 白色珠子什么意思? 在一些项链中还包括白色的珠子(如图片B) 所示。 当收集珠子的时候,一个被遇到的白色珠子可以被当做红色也可以被当做蓝色。 表现含有白珠项链的字符串将会包括三个符号 r,b,w 。 写一个程序来确定从一条被给出的项链可以收集到的珠子最大数目。 输入格式 第一行一个正整数 nn ,表示珠子数目。 第二行一串长度为 nn 的字符串, 每个字符是 r , b 或 w。 输出格式 输出一行一个整数,表示从给出的项链中可以收集到的珠子的最大数量。 输入输出样例 输入 #1复制 29 wwwbbrwrbrbrrbrbrwrwwrbwrwrrb 输出 #1复制 11 说明/提示 【数据范围】 对于 100%100% 的数据,3\le n \le 3503≤n≤350 环的问题是把环复制一个或两个成链解决。 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.youkuaiyun.com/qq_20087731/article/details/104898471解释一下
最新发布
03-21
<think>好的,用户让我解释一个解决USACO Broken Necklace问题的C++代码。首先,我需要理解这个问题本身。题目是关于在一个环形项链上找到一个断点,使得从断点两端收集的珠子最多。珠子颜色有红(r)、蓝(b)和白(w),其中白色可以被当作红或蓝。 用户提供的代码看起来是处理这个问题的典型方法。首先,我需要通读代码,理解各个部分的作用。代码的结构包括头文件、常量和变量的声明,一个函数f(int x),主函数处理输入,将字符串重复三次,然后循环处理每个可能的断点,最后输出结果。 接下来,我需要拆解代码的各个部分。函数f的作用是计算在位置x和x+1之间断开时,能收集到的珠子数目。这里,函数先向左查找相同颜色或白色珠子,然后向右查找,可能包括处理白色珠子的不同可能性。主函数中,将原字符串重复三次,这是处理环形问题的常用方法,通过复制字符串来模拟环状结构,避免处理复杂的环边界条件。 然后,用户的问题中特别提到了白色珠子的处理方式,代码中的部分逻辑可能涉及到将白色珠子尝试替换成红或蓝,以寻找最优解。需要解释为什么这样做是正确的,以及如何确保覆盖所有可能的替换情况。 另外,代码中的一些细节需要注意,比如ans的初始值为-1,最后处理ans的方式,以及如何处理当所有珠子颜色相同的情况。例如,当ans仍然是-1时,将其设为len,这可能是因为所有珠子颜色相同,无法找到断点,所以整个项链都可以收集。 可能存在的疑问点包括:为什么要将字符串复制三次?为什么在循环中处理的是len到2*len的位置?如何确保覆盖所有可能的断点位置?这些都需要在解释中详细说明。 此外,用户之前的问题是关于a = a + a + a; 的代码,而当前代码中也有类似的操作,将a重复三次。可能需要联系之前的解释,说明这里复制三次是为了处理环形结构,使得在展开后的字符串中可以找到所有可能的断点而不必担心越界。 最后,需要确保解释符合用户的要求:结构清晰,步骤分明,使用中文,正确使用LaTeX格式,并且解释代码的逻辑、算法思路以及如何解决问题。同时,需要指出可能的优化点或代码中的注意事项,比如时间复杂度或特殊情况的处理。</think>让我们逐步分析这个解决**坏掉的项链问题**的C++代码实现: --- ### **算法核心思路** **环形处理技巧**:将原字符串复制三次拼接(`a = a + a + a`),使得环形遍历可以转化为线性遍历,避免处理环首尾相连的复杂边界条件。例如原长度为5时,拼接后`[5..10]`区域对应原环的所有可能展开方式。 --- ### **代码结构解析** #### **1. 预处理阶段** ```cpp a = a + a + a; // 三倍展开环形字符串 for(i = len; i < len*2; i++){ // 仅检查中间区域 // ... 核心处理逻辑 } ``` - **为什么三倍复制**:保证展开后的字符串中间部分(`[len, 2*len]`)包含所有可能的断点位置 #### **2. 关键函数`f(x)`** ```cpp int f(int x) { int s = 0; char a1 = a[x], b1 = a[x+1]; // 向左扫描 for(i = x;;i--) { if(a[i]==a1 || a[i]=='w') s++; else break; } // 向右扫描 for(i = x+1;;i++) { if(a[i]==b1 || a[i]=='w') s++; else break; } return s; } ``` - **功能**:计算在位置`x`与`x+1`之间打断时能收集的珠子数 - **扫描规则**: - 左端颜色固定为`a[x]` - 右端颜色固定为`a[x+1]` - `w`可作为任意颜色 #### **3. 白色珠子的特殊处理** ```cpp if(a[i] == 'w') { a[i] = 'r'; ans = max(ans, f(i)); // 尝试视为红色 a[i] = 'b'; ans = max(ans, f(i)); // 尝试视为蓝色 a[i] = 'w'; // 恢复原值 } ``` - **核心逻辑**:当遇到白色珠子时,分别尝试将其视为红色和蓝色,取最大值 #### **4. 边界条件处理** ```cpp ans = min(ans, len); // 防止超过实际长度 if(ans == -1) ans = len; // 全同色情况 ``` - **全同色保护**:当所有珠子颜色相同时,`f(x)`无法触发更新`ans` --- ### **算法流程图** $$ \begin{array}{|c|c|} \hline \text{输入字符串} & \rightarrow \text{三倍展开} \\ \downarrow & \\ \text{遍历中间段每个断点} & \rightarrow \text{处理白色歧义} \\ \downarrow & \\ \text{计算左右可收集长度} & \rightarrow \text{更新最大值} \\ \downarrow & \\ \text{边界修正} & \rightarrow \text{输出结果} \\ \hline \end{array} $$ --- ### **时间复杂度分析** - **主要开销**:对每个断点进行两次线性扫描 - **总复杂度**:$O(n^2)$,其中$n$为珠子数量 - **优化空间**:可通过预处理颜色段信息优化到$O(n)$ --- ### **测试样例解析** 以样例输入`wwwbbrwrbrbrrbrbrwrwwrbwrwrrb`为例: - **最佳断点**:将部分`w`视为红色后,可收集到11个珠子 - **计算过程**: - 左端连续`w`视为红色 - 右端连续`r`和`w`的组合 --- ### **关键优化点说明** - **三倍复制技巧**:避免处理环形索引的模运算 - **白色动态替换**:通过临时修改字符值穷举可能性 - **扫描终止条件**:遇到不同颜色立即停止 该解法充分利用了暴力法的直观性,同时通过字符串复制技巧降低了环形处理的复杂度。对于题目给定的数据范围(n ≤ 350),$O(n^2)$复杂度是可接受的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值