0


「蓝桥杯」

蓝桥杯系列文章目录

  • [ ★] 第一讲 递推与递归

题目目录:

  • [ ★] 第一讲 递推与递归
    • [ ★] 第一题 DFS下的全排列(一题带你搞懂全排列,下面第二种方法作为福利提供给大家,仅此模版,一次搞定全排列)
    • [ ★] 第一讲 递推与递归(一题带你入门开关问题)

我的核心技术者社区

诚邀各位技术爱好者,在本社区,我会尽全力给大家提供一个友好的交流平台。欢迎各位技术爱好者加入。
链接:

  1. https://bbs.csdn.net/forums/CoreTechnologyProvider_TheOne?category=0

一、DFS下的全排列

  1. 1n n 个整数排成一行后随机打乱顺序,输出所有可能的次序。
  2. 输入格式
  3. 一个整数 n
  4. 输出格式
  5. 按照从小到大的顺序输出所有方案,每行 1 个。
  6. 首先,同一行相邻两个数用一个空格隔开。
  7. 其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。
  8. 数据范围
  9. 1n9
  10. 输入样例:
  11. 3
  12. 输出样例:
  13. 1 2 3
  14. 1 3 2
  15. 2 1 3
  16. 2 3 1
  17. 3 1 2
  18. 3 2 1

第一题代码如下:


C++版本1.0
在这里插入图片描述

  1. #include<bits/stdc++.h>usingnamespace std;constint N =10;int state[N];bool used[N];int n;voiddfs(int u)//u代表当前位置{if(u > n)//BaseCase,如果当前位置超出所给数字n,也就是超越边界{for(int i =1; i <= n; i++){
  2. cout << state[i]<<" ";//输出状态数组}
  3. cout << endl;return;}for(int i =1; i <= n; i++){if(!used[i])//当前数字未被应用{
  4. state[u]= i;//当前位置为u的状态数组元素应用数字i
  5. used[i]=true;//标记当前数字已被应用dfs(u +1);//进入下一个位置
  6. state[u]=0;//恢复现场,位置为u的当前状态数组位置设置为0
  7. used[i]=false;//恢复现场,当前数字数字标记为未被应用}}}intmain(){
  8. cin>>n;dfs(1);return0;}

JAVA版本1.0
在这里插入图片描述

  1. import java.util.*;publicclassMain{publicstaticboolean[] used =newboolean[10];publicstaticint n;publicstaticvoidmain(String[] args){
  2. Scanner sc =newScanner(System.in);
  3. n = sc.nextInt();
  4. String[] arr =newString[n +1];for(int i =1; i <= n; i++){
  5. arr[i]= String.valueOf(i);}dfs(1, arr);}publicstaticvoiddfs(int u, String[] state)//u代表当前位置{if(u > n)//BaseCase,如果当前位置超出所给数字n,也就是超越边界{for(int i =1; i <= n; i++){
  6. System.out.print(state[i]+" ");//输出状态数组}
  7. System.out.println();return;}for(int i =1; i <= n; i++){if(!used[i])//当前数字未被应用{
  8. state[u]= String.valueOf(i);//当前位置为u的状态数组元素应用数字i
  9. used[i]=true;//标记当前数字已被应用dfs(u +1, state);//进入下一个位置
  10. state[u]="0";//恢复现场,位置为u的当前状态数组位置设置为0
  11. used[i]=false;//恢复现场,当前数字数字标记为未被应用}}}}

看到这里的朋友会说你写的两个数组是什么鬼东西,有没有更容易理解的。好的,更容易理解的代码如下。


C++版本2.0
友友们,我写了,编译器说我 Segmentation Fault
在这里插入图片描述

  1. #include<bits/stdc++.h>usingnamespace std;int n;
  2. vector<string>removeIndexString(vector<string> arr,int index){
  3. vector<string> x;for(int i =0; i < n ; i++){if(i != index){
  4. x.push_back(arr[i]);}}return x;}
  5. vector<string>process(vector<string> strs){
  6. vector<string> d;if(strs.size()==0){
  7. d.push_back("");return d;}for(int i =0; i < strs.size(); i++){
  8. string first = strs[i];
  9. vector<string> nexts =removeIndexString(strs, i);
  10. vector<string> next =process(nexts);for(string cur : next){
  11. d.push_back((first + cur));}}return d;}intmain(){
  12. cin >> n;
  13. vector<string> arr;for(int i =0; i < n; i++){
  14. arr.push_back((i +1)+"");}
  15. vector<string> ans =process(arr);for(string res : ans){for(int i =0; i < res.size(); i++){
  16. cout << res[i]<<" ";}
  17. cout << endl;}}

JAVA版本2.0
在这里插入图片描述

  1. import java.util.*;publicclassMain{publicstaticvoidmain(String[] args){
  2. Scanner sc =newScanner(System.in);int n = sc.nextInt();
  3. String[] arr =newString[n];for(int i =0; i < n; i++){
  4. arr[i]= String.valueOf(i +1);}
  5. List<String> ans =process(arr);for(String res : ans){char[] an = res.toCharArray();for(int i =0; i < an.length;i++){
  6. System.out.print(an[i]+" ");}
  7. System.out.println();}}publicstatic List<String>process(String[] strs){
  8. List<String> ans =newArrayList<>();//定义一个链表if(strs.length ==0)//如果strs数组中没有元素了,返回空{
  9. ans.add("");return ans;}for(int i =0; i < strs.length; i++){
  10. String first = strs[i];//定义第一位置的元素
  11. String[] nexts =removeIndexString(strs, i);//你把除了第一位置的元素数组给我
  12. List<String> next =process(nexts);//你去把之后位置的元素给我for(String cur : next)//组合,将每个位置的元素进行组合{
  13. ans.add(first + cur);}}return ans;//返回答案链表}publicstatic String[]removeIndexString(String[] arr,int index)//移除index位置的元素后的数组{int N = arr.length;
  14. String[] ans =newString[N -1];int ansIndex =0;for(int i =0; i < N; i++){if(i != index){
  15. ans[ansIndex++]= arr[i];}}return ans;}}

二、递推之飞行兄弟

递推之飞行兄弟,对于开关问题,首先确定所有可能性,然后尝试枚举每一种可能性。


  1. “飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有 16 个把手的冰箱。
  2. 已知每个把手可以处于以下两种状态之一:打开或关闭。
  3. 只有当所有把手都打开时,冰箱才会打开。
  4. 把手可以表示为一个 4×4 的矩阵,您可以改变任何一个位置 [i,j] 上把手的状态。
  5. 但是,这也会使得第 i 行和第 j 列上的所有把手的状态也随着改变。
  6. 请你求出打开冰箱所需的切换把手的次数最小值是多少。
  7. 输入格式
  8. 输入一共包含四行,每行包含四个把手的初始状态。
  9. 符号 + 表示把手处于闭合状态,而符号 - 表示把手处于打开状态。
  10. 至少一个手柄的初始状态是关闭的。
  11. 输出格式
  12. 第一行输出一个整数 N,表示所需的最小切换把手次数。
  13. 接下来 N 行描述切换顺序,每行输出两个整数,代表被切换状态的把手的行号和列号,数字之间用空格隔开。
  14. 注意:如果存在多种打开冰箱的方式,则按照优先级整体从上到下,同行从左到右打开。
  15. 数据范围
  16. 1i,j4
  17. 输入样例:
  18. -+--
  19. ----
  20. ----
  21. -+--
  22. 输出样例:
  23. 6
  24. 1 1
  25. 1 3
  26. 1 4
  27. 4 1
  28. 4 3
  29. 4 4

第二题代码如下:


C++版本1.0

  1. #include<bits/stdc++.h>#define x first#define y secondusingnamespace std;constint N =5;char g[N][N], backup[N][N];//数组元素位置如下图进行标记//[0, 1, 2, 3]//[4, 5, 6, 7]//[8, 9, 10, 11]//[12, 13, 14, 15]intget(int x,int y)//获取坐标为(x,y)的数组元素所在的位置{return x *4+ y;}voidturnOne(int x,int y)//将坐标为(x, y)的元素进行反转{if(g[x][y]=='+') g[x][y]='-';else g[x][y]='+';}voidturnAll(int x,int y)//因为反转一个开关,会把该位置开关所在行和所在列全部进行反转{for(int i =0; i <4; i++){turnOne(x, i);turnOne(i, y);}turnOne(x, y);//因为坐标为(x,y)的开关被反转了两次,相当于没有反转,所以在反转一次}intmain(){for(int i =0; i <4; i++) cin >> g[i];//输入给定的4X4的矩阵
  2. vector<pair<int,int>> res;//定义答案数组for(int op =0; op <1<<16; op++)//因为有16个开关,每个开关有打开和关闭两个选择,所以全部的可能性为2^16 - 1{
  3. vector<pair<int,int>> temp;//定义辅助数组memcpy(backup, g,sizeof g);//将g矩阵进行拷贝,因为每一次操作之后需要复原,方便进行下一次可能性for(int i =0; i <4; i++)for(int j =0; j <4; j++)if(op >>get(i, j)&1)//模拟每种可能性,1代表打开,0代表关闭{
  4. temp.push_back({ i, j });//将坐标为(i,j)的开关打开turnAll(i, j);//反转坐标为(i,j)的开关所在行和所在列}bool isClosed =false;//定义标记isClosed,用来判断所有元素是否全部打开,即所有元素全部为‘-’for(int i =0; i <4; i++)for(int j =0; j <4; j++)if(g[i][j]=='+')
  5. isClosed =true;if(isClosed ==false)//如果所有开关全部打开{if(res.empty()|| res.size()> temp.size())//如果答案数组为空,或者答案数组的元素个数大于临时数组的元素个数,证明答案数组的结果不是最优解,进行替换{
  6. res = temp;}}memcpy(g, backup,sizeof g);}
  7. cout << res.size()<< endl;//输出答案数组元素个数for(auto op : res){
  8. cout << op.x +1<<' '<< op.y +1<< endl;//因为我们是从零下表开始,答案是从一下标开始,所以将答案数组中的下标全部加一即可}return0;}

JAVA版本1.0

  1. import java.util.ArrayList;import java.util.List;import java.util.Scanner;publicclasstst{//数组元素位置如下图进行标记//[0, 1, 2, 3]//[4, 5, 6, 7]//[8, 9, 10, 11]//[12, 13, 14, 15]publicstaticclassPair{//定义Pair类,用来记录每个开关的位置信息int x;int y;publicPair(int o1,int o2){this.x = o1;this.y = o2;}}publicstaticintget(int x,int y)//获取坐标为(x,y)的数组元素所在的位置{return x *4+ y;}publicstaticvoidturnOne(char[][] ch,int x,int y)//将坐标为(x, y)的元素进行反转{
  2. ch[x][y]= ch[x][y]=='+'?'-':'+';}publicstaticvoidturnAll(char[][] ch,int x,int y)//因为反转一个开关,会把该位置开关所在行和所在列全部进行反转{for(int i =0; i <4; i++){turnOne(ch, x, i);turnOne(ch, i, y);}turnOne(ch, x, y);//因为坐标为(x,y)的开关被反转了两次,相当于没有反转,所以在反转一次}publicstaticvoidcopyArray(char[][] ch,char[][] help){for(int i =0; i < ch.length; i++){for(int j =0; j < ch[0].length; j++){
  3. help[i][j]= ch[i][j];}}}publicstaticvoidmain(String[] args){
  4. Scanner sc =newScanner(System.in);char[][] ch =newchar[4][4];char[][] help =newchar[4][4];
  5. List<Pair> ans =newArrayList<>();//定义答案链表int allOp =1<<16;//因为有16个开关,每个开关有打开和关闭两个选择,所以全部的可能性为2^16 - 1for(int i =0; i <4; i ++){
  6. String str = sc.next();for(int j =0; j <4; j++){
  7. ch[i][j]= str.charAt(j);}}for(int op =0; op < allOp; op++){
  8. List<Pair> res =newArrayList<>();//定义辅助链表copyArray(ch, help);//将g矩阵进行拷贝,因为每一次操作之后需要复原,方便进行下一次可能性for(int i =0; i <4; i++){for(int j =0; j <4; j++){if(((op >>get(i, j))&1)==1)//模拟每种可能性,1代表打开,0代表关闭{
  9. res.add(newPair(i, j));//将坐标为(i,j)的开关打开,并加入临时链表turnAll(ch, i, j);//反转坐标为(i,j)的开关所在行和所在列}}}boolean isClosed =false;//定义标记isClosed,用来判断所有元素是否全部打开,即所有元素全部为‘-’for(int i =0; i <4; i ++){for(int j =0; j <4; j++){if(ch[i][j]=='+'){
  10. isClosed =true;}}}if(isClosed ==false)//如果所有开关全部打开{if(ans.isEmpty()||(ans.size()> res.size()))//如果答案数组为空,或者答案数组的元素个数大于临时数组的元素个数,证明答案数组的结果不是最优解,进行替换{
  11. ans = res;}}copyArray(help,ch);}
  12. System.out.println(ans.size());//输出答案链表元素个数for(Pair op : ans){
  13. System.out.println((op.x+1)+" "+(op.y+1));//因为我们是从零下表开始,答案是从一下标开始,所以将答案链表中的下标全部加一即可}}}

尾语

抱歉,我最近有些忙,博客会陆续补上。谢谢大家!

标签: 蓝桥杯 算法

本文转载自: https://blog.csdn.net/qq_45992664/article/details/123524924
版权归原作者 陌芮 所有, 如有侵权,请联系我们删除。

“「蓝桥杯」”的评论:

还没有评论