目录
砖块
nn 个砖块排成一排,从左到右编号依次为 1∼n1∼n。
每个砖块要么是黑色的,要么是白色的。
现在你可以进行以下操作若干次(可以是 00 次):
选择两个相邻的砖块,反转它们的颜色。(黑变白,白变黑)
你的目标是通过不超过 3n3n 次操作,将所有砖块的颜色变得一致。
输入格式
第一行包含整数 TT,表示共有 TT 组测试数据。
每组数据第一行包含一个整数 nn。
第二行包含一个长度为 nn 的字符串 ss。其中的每个字符都是 W
或 B
,如果第 ii 个字符是 W
,则表示第 ii 号砖块是白色的,如果第 ii 个字符是 B
,则表示第 ii 个砖块是黑色的。
输出格式
每组数据,如果无解则输出一行 −1−1。
否则,首先输出一行 kk,表示需要的操作次数。
如果 k>0k>0,则还需再输出一行 kk 个整数,p1,p2,…,pkp1,p2,…,pk。其中 pipi 表示第 ii 次操作,选中的砖块为 pipi 和 pi+1pi+1 号砖块。
如果方案不唯一,则输出任意合理方案即可。
数据范围
1≤T≤101≤T≤10,
2≤n≤2002≤n≤200。
输入样例:
4
8
BWWWWWWB
4
BWBB
5
WWWWW
3
BWB
输出样例:
3
6 2 4
-1
0
2
2 1
解析:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int n,T;
string str;
void update(char &c)
{//交换字母 如果是W就改为B 如果是B就改为W
if(c=='W')c='B';
else c='W';
}
bool check(char c)
{
string s=str;
vector<int>ans;//用来存取进行变换的下标
for(int i=0;i+1<n;i++)
{
if(s[i]!=c){//从左到右遍历 如果当前字符不等于目标字符 则将当前字符和后面一个字符进行转换
update(s[i]);
update(s[i+1]);
ans.push_back(i);//将当前变换下标进行存储
}
}
if(s.back()!=c)return false;//最后一个字符不等于目标字符 则表示 无法全部转换为c
cout<<ans.size()<<endl;//转换次数
for(auto x:ans)cout<<x+1<<' ';//因为题目下标由1开始 记得+1
if(ans.size())cout<<endl;
return true;
}
int main()
{
cin>>T;
while (T -- ){
cin>>n>>str;
if(!check('B')&&!check('W'))cout<<-1<<endl;//如果将字符串转换为全B和全W都失败 则无解输出-1
}
return 0;
}
翻硬币(第四届蓝桥杯省赛C++B组)
小明正在玩一个“翻硬币”的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:**oo***oooo
如果同时翻转左边的两个硬币,则变为:oooo***oooo
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作。
输入格式
两行等长的字符串,分别表示初始状态和要达到的目标状态。
输出格式
一个整数,表示最小操作步数
数据范围
输入字符串的长度均不超过100。
数据保证答案一定有解。
输入样例1:
**********
o****o****
输出样例1:
5
输入样例2:
*o**o***o***
*o***o**o***
输出样例2:
1
解析:
#include<iostream>
using namespace std;
string a,b;
int main()
{
cin>>a>>b;
int n=a.size();
int ans=0;
//从左往右遍历
for(int i=0;i+1<n;i++)
{//当前字符与目标字符不同
if(a[i]!=b[i]){
if(a[i]=='*')a[i]='o';
else a[i]='*';//翻转当前硬币
if(a[i+1]=='*')a[i+1]='o';
else a[i+1]='*';//翻转下一个硬币
ans++;//次数+1
}
}
cout<<ans<<endl;
return 0;
}
树的遍历
一个二叉树,树中每个节点的权值互不相同。
现在给出它的后序遍历和中序遍历,请你输出它的层序遍历。
输入格式
第一行包含整数 NN,表示二叉树的节点数。
第二行包含 NN 个整数,表示二叉树的后序遍历。
第三行包含 NN 个整数,表示二叉树的中序遍历。
输出格式
输出一行 NN 个整数,表示二叉树的层序遍历。
数据范围
1≤N≤301≤N≤30,
官方并未给出各节点权值的取值范围,为方便起见,在本网站范围取为 1∼N1∼N。
输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例:
4 1 6 3 5 7 2
解析:
#include<iostream>
#include <vector>
using namespace std;
const int N = 35;
vector<int>level[N];
int n;
int a[N],b[N],p[N];//a记录后序 b记录中序 p[i]记录i号结点在中序遍历的位置下标
void build(int al,int ar,int bl,int br,int d)
{//al 为后序遍历左端点 ar为后序遍历右端点 bl为中序遍历左端点 br为中序遍历右端点 d为层数
if(al>ar)return ;//当左端点大于右端点
int val=a[ar];//根节点为后续遍历的最后一个结点
level[d].push_back(val);//当前层加入结点 因为层序遍历 所以下面要先遍历左节点在遍历右节点
int k=p[val];//找到val在中序遍历的下标
build(al,k-1-bl+al,bl,k-1,d+1);//遍历左子树
//左子树--后序的左端点不变 中序左端点不变 中序右端点为k-1 层数+1
//左子树--后序右端点-后序左端点=中序右端点-中序左端点 得到后序右端点=中序右端点-中序左端点+后序左端点 即k-1-bl+al
build(k-bl+al,ar-1,k+1,br,d+1);//遍历右子树
//右子树的后序左端点为左子树后序右端点+1 右端点为ar-1 中序遍历右子树左端点为k+1 右端点为br 层数+1
//最难就在于求出后序遍历左子树的右端点 这边建议画一个图会清晰很多
}
int main()
{
cin>>n;
for (int i = 0; i < n; i ++ )cin>>a[i];
for (int i = 0; i < n; i ++ )cin>>b[i];
for (int i = 0; i < n; i ++ )p[b[i]]=i;//记录值为b[i]在b中的下标
build(0,n-1,0,n-1,0);
for(int i=0;i<n;i++)
for(auto x:level[i])//按序输出每一层的结果
cout<<x<<' ';
return 0;
}