2020蓝桥杯校赛部分题解

n对括号的合法括号序列数量

问题描述
由1对括号,可以组成一种合法括号序列: ()。
由2对括号,可以组成两种合法括号序列: ()(),(())。由4对括号组成的合法括号序列一共有多少种?
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的多余的内容将无法得分。

思路:

括号对的合法序列,已经插入的左括号的数目大于等于右括号的数目。

(1)插入左括号:剩余的括号中,还有左括号;

(2)插入右括号:剩余的括号中,右括号的数目大于左括号的数目;

答案:14

代码:

其实这个递归中的r>l可以替换成r>1,因为此代码是优先摆放左括号,在第一次(((())))进行完往外跳出时,进入递归函数还是先看是否还有左括号,有就先添加左括号!有点类似于子集树,每个位置也是要么左括号,要么是右括号!然后在搜索之前加上符合本题的限定条件就ok了!!!

可以参考这篇文章(戳这里!)

public class Main1 {
	static int num=0;
	public static void printPar(int l, int r, char[] str, int count){
		if(l<0 || r<l){ //注意是r<l不是r<1
			return;
		}
		if(l==0&&r==0){
			num++;
			System.out.println(str);//char数组可直接如此打印
		}else{
			if(l>0){
				str[count]='(';
				printPar(l-1, r, str, count+1);
			}
			if(r>l){//注意是>l,不是>1,即剩余右括号的数量大于左括号的数量
				str[count]=')';
				printPar(l, r-1, str, count+1);
			}
		}
		
	}
	
	public static void main(String[] args){
		int count = 4;
		char str[] = new char[count*2];
		printPar(count, count, str, 0);
		System.out.println(num);
	}
}

运行结果

(((())))
((()()))
((())())
((()))()
(()(()))
(()()())
(()())()
(())(())
(())()()
()((()))
()(()())
()(())()
()()(())
()()()()
14

通过第一次跳出(第一行到第二行的转变也易知),一直往上跳出直到遇到有左括号,可以自己画一棵简单的两对括号的二叉树加深以下理解,易知2对括号就两条路可走。


梅花桩

题意:

从(1,1)走到(m,n),最大移动距离为d(d>=1),求最少移动次数

第一行输入m和n,第二行输入d
输入样例:
3 4
1.5
输出样例:

3

自己当时做的时候是直接分情况讨论了,先斜着走,再直着走,不知道对不对。

借鉴大佬的dfs代码如下:

15 15

1.4 会超时,不会宽搜,宽搜好像不超时

import java.util.Scanner;
public class Main {
	static int m,n;
    static double d;
    static int min=Integer.MAX_VALUE;
    static void dfs(int x,int y,int step){//利用step记录每个可行解的走的步数
    	if(x>m||y>n||step>min){//没有到达(m,n)点或者走到这的步数已经比已知的最少的步数多了,则不再往下搜索
    		return;
    	}
    	else if(x==m&&y==n&&step<min){//到达(m,n)点且此次步长比之前最少的步数要少
    		min=step;
    	}
    	else{//向(m,n)方向搜索,因为斜相邻的两个格子之间距离是根号2,所以当d>根号2时,可以斜着走
    		for(int i=0;i<=d;i++){
    			for(int j=0;j<=d;j++){
    				if((i*i+j*j)>0&&(i*i+j*j)<=d*d){
   /*此处不能是step++或者++step,因为从每个点出发的下一步可能有三种选择
      所以step不能改变,只能传参step+1
    */
    					dfs(x+i,y+j,step+1);
    				}
    			}
    		}
    	}
    }
    
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        Scanner in=new Scanner(System.in);
		m=in.nextInt();
		n=in.nextInt();
		d=in.nextDouble();
		dfs(1,1,0);
		System.out.println(min);
	}

}

第九题

问题描述
  小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。
  小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。
  这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块空地都将变为有草的小块。
  请告诉小明,k 个月后空地上哪些地方有草。
输入格式
  输入的第一行包含两个整数 n, m。
  接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
  接下来包含一个整数 k。
输出格式
  输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。
样例输入
4 5
.g...
.....
..g..
.....
2
样例输出
gggg.
gggg.
ggggg
.ggg.
评测用例规模与约定
  对于 30% 的评测用例,2 <= n, m <= 20。
  对于 70% 的评测用例,2 <= n, m <= 100。
  对于所有评测用例,2 <= n, m <= 1000,1 <= k <= 1000。
JAVA

思路:

递归。。。刷题量不多就是不行,当时第一反应并查集可不可以做,因为前一天晚上刚好看了看并查集,再一看好像直接暴力就行,于是我就开始暴力到最后结束。。

暴力的话写了三重for循环,但是结果竟然从第一天就全是g了,一想是因为for是遍历了每个点,有的点刚被扩散长出草来又因为遍历到它,它又开始向四周扩散,所以才会将正片空地全部种上草!!!

于是我又想设一个note数组来记录每天向四周扩展的空地,无奈打表查看第一天对了,第二天又不对了。

晚上在想用递归试试,然后就过了。。用递归直接从每个初始种草点开始扩散就行,简单易懂

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
public class Main {
	static int k,n,m;//扩散 k次
	static void dfs(String[][] a,int i,int j,int count){ 
		if(count>k){//每块种草的空地从开始到结束只扩展k天!!!
			return;
		}
		if(j-1>=0){
			a[i][j-1]="g";
			dfs(a,i,j-1,count+1);
		}
		if(j+1<m){
			a[i][j+1]="g";
			dfs(a,i,j+1,count+1);
		}
		if(i-1>=0){
			a[i-1][j]="g";
			dfs(a,i-1,j,count+1);
		}
		if(i+1<n){
			a[i+1][j]="g";
			dfs(a,i+1,j,count+1);
		}
	}
	
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		String s=br.readLine();
		String b[]=s.split(" ");
		n=Integer.parseInt(b[0]);
		m=Integer.parseInt(b[1]);

		String[][] a=new String[n][m];
		for(int i=0;i<n;i++){
			String str=br.readLine();
		    String[] tmp=str.split("");
		    tmp=Arrays.copyOfRange(tmp,1,tmp.length);//把第一个空串去除
		    a[i]=Arrays.copyOf(tmp,tmp.length);
		}
		k=Integer.parseInt(br.readLine());
		ArrayList<Integer> list=new ArrayList<Integer>();//横坐标
		ArrayList<Integer> list1=new ArrayList<Integer>();//纵坐标
		//将最初种草的那几块空地坐标保存就行
			for(int i=0;i<n;i++){
				for(int j=0;j<m;j++){
					if(a[i][j].equals("g")){
					   list.add(i);
					   list1.add(j);
					}
				}
			}
		int L=list.size();
		for(int i=0;i<L;i++){
			//System.out.println(list.remove(list.size()-1)+" "+list1.remove(list.size()-1));
			//让每个初始点向四周扩散就行!!!
			dfs(a,list.get(L-i-1),list1.get(L-i-1),1);
			list.remove(L-i-1);
			list1.remove(L-i-1);
		}

		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				System.out.print(a[i][j]);
			}
			System.out.println();
		}
	}

}
发布了81 篇原创文章 · 获赞 91 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44593822/article/details/103434653