Broken necklace

本文介绍了一个使用C++编程解决珠串问题的方法,通过连接两个字符串并找到最长的连续相同颜色序列。

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

/*
ID: boyshan1
PROG: beads
LANG: C++
*/
#include <iostream>
#include <fstream>
using namespace std;
int Collect(char necklace[],int length)
{
char necklace2[700];
int n;
for(n=0;n<2*length;n++)//连接两个串
{
if(n>=length)
necklace2[n]=necklace[n-length];
else necklace2[n]=necklace[n];
}


int i=0,j,k,num=0;int Max=0;
char  color,color2;
bool c1=false,c2=false;
while(i<n)
{
for(j=i;j>=0;j--)//从当前位置往前遍历
{
if(necklace2[j]!='w'&&c1==false)
{
color=necklace2[j];//遇见第一个不是w的颜色记录下来
c1=true;
}
if(necklace2[j]!='w'&&c1==true&&necklace2[j]!=color)break;//继续向前走,遇到既不是"w",又不是该颜色就跳出
num++;
}
for(k=i+1;k<n;k++)//从当前位置向后遍历
{
if(necklace2[k]!='w'&&c2==false&&necklace2[k]!=color)//遇见第一个既不是w也不是上面已记录的颜色,记录下来
{
color2=necklace2[k];
c2=true;
}
if(k==length&&c2==true&&necklace2[k+1]!='w')break;  //两个串交接处的处理
if(necklace2[k]!='w'&&c2==true&&necklace2[k]!=color2)break;//继续向后走,遇到既不是w又不是该颜色跳出
num++;
}
if(num>=n)  //处理字符串中只有一种颜色的情况
Max=length;
else if(i>=length&&necklace2[i]!='w'&&necklace2[i+1]!='w'&&necklace2[i]!=necklace2[i+1])break;//如果两个串的交接处颜色不同,且二者没有谁是w,就没必要往下检查了
else
if(num>Max)
{
Max=num;
num=0;
c1=false;
c2=false;
}
else    
{
num=0;
c1=false;
c2=false;
}
i++;
}
return Max;
}
int main()
{
ofstream fout("beads.out");
    ifstream fin("beads.in");
int N,i=0;
char neck[350];
while(fin>>N)
{
while(i<N)
{
fin>>neck[i];
i++;
}
fout<<Collect(neck,N)<<endl;
i=0;
}
return 0;
}
#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、付费专栏及课程。

余额充值