作者:指针不指南吗
专栏:Acwing 蓝桥集训每日一题🐾或许会很慢,但是不可以停下来🐾
递推算法是一种简单的算法,通过已知条件,利用特定关系得出中间推论,逐步递推,直到得到结果为止
1.砖块
n 个砖块排成一排,从左到右编号依次为 1∼n。
每个砖块要么是黑色的,要么是白色的。
现在你可以进行以下操作若干次(可以是 00 次):
选择两个相邻的砖块,反转它们的颜色。(黑变白,白变黑)
你的目标是通过不超过 3n 次操作,将所有砖块的颜色变得一致。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含一个整数 n。
第二行包含一个长度为 n 的字符串 s。其中的每个字符都是
W
或B
,如果第 i 个字符是W
,则表示第 i 号砖块是白色的,如果第 i 个字符是B
,则表示第 i 个砖块是黑色的。输出格式
每组数据,如果无解则输出一行 −1。
否则,首先输出一行 k,表示需要的操作次数。
如果 k>0,则还需再输出一行 k 个整数,p1,p2,…,pk。其中 pi 表示第 i 次操作,选中的砖块为 pi 和 pi+1 号砖块。
如果方案不唯一,则输出任意合理方案即可。
数据范围
1≤T≤10,
2≤n≤200。输入范围:
4 8 BWWWWWWB 4 BWBB 5 WWWWW 3 BWB
输出样例:
3 6 2 4 -1 0 2 2 1
-
思路
-
最后的结果可以分成两种情况:全白或者是全黑;
-
我们操作的位置只有 n-1 种,所以不用考虑 3n 的情况;
-
每个位置反转两次,相当于没有反转,所以我们只要考虑每个位置要不要操作就可以(0或者1);
-
如果 i 位置和我们想要的颜色不同,则操作,否则,不,所以说每个位置的操作都是确定的;
把每一个位置递推一下,到最后一个
- 最后一个在前一个位置操作或者是没有操作过后,不能操作:判断一下,如果与第一个相同,则说明符合题意。
-
-
代码实现
#include<bits/stdc++.h> using namespace std; int n; void update(char &a) { if(a=='W') a='B'; else a='W'; } bool check(string s,char x) { vector<int> ans; //数组 ans 存操作的位置 for(int i=0;i+1<n;i++){ if(s[i]!=x){ //如果不是我们想要的,则更新 update(s[i]); update(s[i+1]); ans.push_back(i); //把操作位置放入数组中 } } if(s.back()!=s[0]) return false; //最后一个无法改变,如果与前面不同,则不能实现 cout<<ans.size()<<endl; for(auto i:ans) cout<<i+1<<' '; //输出结果 return true; } int main() { int T; cin>>T; while(T--){ string s; cin>>n>>s; if(!check(s,'W')&&!check(s,'B')) puts("-1"); //如果全白或者是全黑都不可以,则输出 -1; } return 0; }
2.翻硬币
小明正在玩一个“翻硬币”的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:
**oo***oooo
如果同时翻转左边的两个硬币,则变为:
oooo***oooo
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作。
输入格式
两行等长的字符串,分别表示初始状态和要达到的目标状态。
输出格式
一个整数,表示最小操作步数
数据范围
输入字符串的长度均不超过100。
数据保证答案一定有解。输入样例1:
********** o****o****
输出样例1:
5
输入样例2:
*o**o***o*** *o***o**o***
输出样例2:
1
-
思路
这个题其实很简单,和上一个很类似,几乎一模一样。
翻硬币,翻一个位置,那么操作的时候,必须这个和下一个连体操作。
由于,一个位置上的硬币,翻两次相当于没有翻,所以一个硬币只有翻一次和不翻两种情况。
从第一个位置上开始,如果和目标字符不一样就翻,一样则下一个,操作一次cnt++,最后输出cnt。
-
代码实现
#include<bits/stdc++.h> using namespace std; string a,b; void update (char &c) //对某一硬币操作的时候,这里一定要引用!!!不然相当于没改!!! { if(c=='o') c='*'; else c='o'; } int main() { cin>>a; cin>>b; //读入数据 int n=a.size(); //n表示硬币数 int cnt=0; for(int i=0;i<n;i++) //从第一个位置上的硬币开始,和目标字符一样,则下一个;不一样,则操作 { if(a[i]!=b[i]){ update(a[i]); update(a[i+1]); cnt++; //记录操作的次数 } } cout<<cnt; //输出结果 return 0; }