Winter Vacation Training(1st Week)

7-1 子集和问题 (50分)

设集合S={x1,x2,…,xn}是一个正整数集合,c是一个正整数,子集和问题判定是否存在S的一个子集S1,使S1中的元素之和为c。试设计一个解子集和问题的回溯法。

输入格式:

输入数据第1行有2个正整数n和c,n表示S的大小,c是子集和的目标值。接下来的1行中,有n个正整数,表示集合S中的元素。 是子集和的目标值。接下来的1 行中,有n个正整数,表示集合S中的元素。

输出格式:

输出子集和问题的解,以空格分隔,最后一个输出的后面有空格。当问题无解时,输出“No Solution!”。

输入样例:

在这里给出一组输入。例如:

5 10
2 2 6 5 4

输出样例:

在这里给出相应的输出。例如:

2 2 6 

 思路:

一道老题就不多赘述了。主要说一下递归中如何强制跳出整个递归(详见代码)。

利用异常跳出整个递归。先写一个静态的StopMsgException类,再继承RuntimeException类,主函数调用递归部分直接而try,catch,注意catch里是StopMsgException e,最后递归里需要跳出的地方用throw StopMsgException抛出异常就ok了。

用return是无法跳出递归的,只会返回上一级!!!

怎么剪枝优化最后一个点都超时,比赛的时候给1s应该没问题,不必管他了。

dfs的else里的优化其实不用那么复杂,前四个个点如下简单优化也过了。。

                        x[loc]=1;
			if(add+a[loc]<=c){
				dfs(a,n,c,loc+1,x,add+a[loc]);
			}
			x[loc]=0;
			if(add<c){
				dfs(a,n,c,loc+1,x,add);
			}
import java.util.ArrayList;
import java.util.Scanner;
public class 子集和问题 {
	
	static class StopMsgException extends RuntimeException{
		
	}
	static Boolean flag=false;
	static ArrayList<Integer> list=new ArrayList<Integer>();
	static void dfs(int[] a,int n,int c,int loc,int[] x,int add){
		if(loc>=n){//得到一个解
			int sum=0;
			for(int i=0;i<n;i++){
				if(x[i]==1){
					sum+=a[i];
					list.add(a[i]);
				}
			}
			if(sum==c){
				flag=true;
				for(int i:list){
					System.out.print(i+" ");
				}
				throw new StopMsgException();
			}
			else{
				list.clear();
			}
		}
		else{
			x[loc]=1;
			if(add+a[loc]==c){
				flag=true;
				for(int i=0;i<n;i++){
					if(x[i]==1){
						System.out.print(a[i]+" ");
					}
				}
				throw new StopMsgException();
			}
			if(add+a[loc]<c){
				dfs(a,n,c,loc+1,x,add+a[loc]);
			}
			x[loc]=0;
			if(add+a[loc]==c){
				flag=true;
				for(int i=0;i<n;i++){
					if(x[i]==1){
						System.out.print(a[i]+" ");
					}
				}
				throw new StopMsgException();
			}
			if(add<c){
				dfs(a,n,c,loc+1,x,add);
			}
		}
	}

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        int c=in.nextInt();
        int[] a=new int[n];
        for(int i=0;i<n;i++){
        	a[i]=in.nextInt();
        }
        int[] x=new int[n];//元素只有1或0,用来记录元素有或者没有
        try{
        	dfs(a,n,c,0,x,0);
        }catch(StopMsgException e){
     
        }
        
        if(!flag){
        	System.out.println("No Solution!");
        }
	}

}

7-3 前序序列创建二叉树 (25分)

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以二叉链表存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,代表一棵空树。然后再对二叉树进行中序遍历,输出遍历结果。

输入格式:

多组测试数据,每组测试数据一行,该行只有一个字符串,长度不超过100。

输出格式:

对于每组数据,

输出二叉树的中序遍历的序列,每个字符后面都有一个空格。

每组输出一行,对应输入的一行字符串。

输入样例:(及其对应的二叉树)

snap858.jpg

abc##de#g##f###

输出样例:

c b e g d f a 

 虽然树的题平时没怎么做过,但是毕竟有数据结构的基础在,解题一看就懂了,不过这题得多敲,掌握如何构造树的结构,第一遍敲出了好多bug。

注意在中序遍历时if一定要包含全部的代码,以防出现空指针异常!

import java.util.Scanner;

public class 前序序列创建二叉树 { 
	static int i,length;
	static String str;
	static Node create(){//先序创建树
		Node o=null;
		if(i<length){
			o=new Node();
			o.mark=str.charAt(i);
			i++;
			if(o.mark!='#'){
				o.left=create();
				o.right=create();
			}
		}
		return o;
	}
	static void midTraversal(Node o){//中序遍历输出
		//此处必须全部包含起来要不有空指针异常,
		//因为如果o没有左孩子或右孩子,那么函数传入的就是null
		if(o.mark!='#'){
			midTraversal(o.left);
			System.out.print(o.mark+" ");
			midTraversal(o.right);
		}
	}

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        Scanner in=new Scanner(System.in);
        while(true){
        	i=0;
        	str=in.nextLine();
            length=str.length();
            Node root=create();
            midTraversal(root);
            System.out.println();
        }
	}

}
class Node{//定义结点结构
	char mark;
	Node left=null;
	Node right=null;
}

7-4 电路布线 (20分)

在解决电路布线问题时,一种很常用的方法就是在布线区域叠上一个网格,该网格把布线区域划分成m*n个方格,布线时,转弯处必须采用直角,如已经有某条线路经过一个方格时,则在该方格上不允许叠加布线。如下图所示,如从一个方格a(2,1)的中心点到另一个方格b(8,8)的中心点布线时, 每个方格布线时需要1个单位的电路材料,所需要最少的电路材料是16。

电路布线.jpg

输入格式:

第一行输入网格的m和n

第二行开始输入网格中已经布线的情况,如果已经有布线时,用1表示,尚未布线时,用0表示。

接下来两行分别输入需要布线的起始位置a和结束位置b。

输出格式:

输出从起始位置a到结束位置b布线时所需要的最少电路材料。

输入样例:

在这里给出一组输入。例如:

8 8
1 1 1 1 1 1 1 1
0 0 0 0 0 1 1 1
1 0 1 1 0 0 0 1
1 0 1 1 0 1 1 0
1 0 1 1 1 1 1 1
1 0 1 1 0 0 0 1
1 0 0 0 0 1 0 0
1 1 1 1 1 1 1 0
2 1
8 8

输出样例:

在这里给出相应的输出。例如:

16

 思路:

又一道老题,就是个迷宫,用深搜找最短路径的话就得把每一条路都找出来,然后取其中最短的一条,即每找到一条路都得比较!注意static int shortest=m*n;是错误的写法,此时m,n还没有赋值,所以shortest这样写,初值就是0,得等到m,n复制之后,再将shortest=m*n;

import java.util.Scanner;
public class 电路布线 {
	static int m,n;
	static int shortest;
	static void dfs(int[][] a,int i,int j,int e1,int e2,int count){
		if(i==e1&&j==e2){//到达终点
//			System.out.println(count);
			if(shortest>count){
				shortest=count;
			}
		}
		else{
			if(j-1>=0&&a[i][j-1]!=1){
				a[i][j-1]=1;
				dfs(a,i,j-1,e1,e2,count+1);
				a[i][j-1]=0;
			}
			if(j+1<n&&a[i][j+1]!=1){
				a[i][j+1]=1;
				dfs(a,i,j+1,e1,e2,count+1);
				a[i][j+1]=0;
			}
			if(i-1>=0&&a[i-1][j]!=1){
				a[i-1][j]=1;
				dfs(a,i-1,j,e1,e2,count+1);
				a[i-1][j]=0;
			}
			if(i+1<m&&a[i+1][j]!=1){
				a[i+1][j]=1;
				dfs(a,i+1,j,e1,e2,count+1);
				a[i+1][j]=0;
			}
		}
	}

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        Scanner in=new Scanner(System.in);
        m=in.nextInt();
        n=in.nextInt();
        shortest=m*n;
        int metrix[][]=new int[m][n];
        for(int i=0;i<m;i++){
        	for(int j=0;j<n;j++){
        		metrix[i][j]=in.nextInt();
        	}
        }
        int start1=in.nextInt()-1;
        int start2=in.nextInt()-1;
        int end1=in.nextInt()-1;
        int end2=in.nextInt()-1;
        dfs(metrix,start1,start2,end1,end2,1);//起点就需要一单位的电线,所以置为1
        System.out.println(shortest);
	}

}

7-6 删除数组零元素 (10分)

从键盘读入n个整数放入数组中,编写函数CompactIntegers,删除数组中所有值为0的元素,其后元素向数组首端移动。注意,CompactIntegers函数需要接受数组及其元素个数作为参数,函数返回值应为删除操作执行后数组的新元素个数。输出删除后数组中元素的个数并依次输出数组元素。

输入格式:

输入格式说明:5为输入数据的个数,3 4 0 0 2 是以空格隔开的5个整数

输出格式:

请3为非零数据的个数,3 4 2 是以空格隔开的3个非零整数

输入样例:

在这里给出一组输入。例如:

5 
3 4 0 0 2

输出样例:

在这里给出相应的输出。例如:

3
3 4 2

思路:

一道基础小题,用来加强优化时间的意识还不错。

import java.util.*;
public class 删除数组零元素 {
	static int count=0;
	static int CompactIntegers(int[] a,int n){
		for(int i=0;i<n-count;i++){//遍历长度要随之更改,优化时间
			if(a[i]==0){
				count++;
				for(int j=i;j<n-1;j++){
					a[j]=a[j+1];
				}
				i--;//防止下一个0前进到了此位置
			}
			
		}
		return n-count;
	}

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        Scanner in=new Scanner(System.in);
        int n=in.nextInt();
        int[] a=new int[n];
        for(int i=0;i<n;i++){
        	a[i]=in.nextInt();
        }
        int L=CompactIntegers(a,n);
        System.out.println(L);
        for(int i=0;i<L-1;i++){
        	System.out.print(a[i]+" ");
        }
        System.out.println(a[L-1]);
	}

}

7-8 最大最小公倍数 (10分)

已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。

数据规模与约定

1 <= N <= 106。

输入格式:

输入一个正整数N。

输出格式:

输出一个整数,表示你找到的最小公倍数。

输入样例:

在这里给出一组输入。例如:

9

输出样例:

在这里给出相应的输出。例如:

504

 思路:找子集,然后计算数量为三的子集的最小公倍数(辗转相除法求最大公约数,a,b的最小公倍数=a*b/(a,b的最大公约数),然后再让求出来的那个最小公倍数和第三个数求最小公倍数),每次比较最后找最大的就可以了,不知道为啥样例过了,但测试点全错?????什么鬼

import java.util.Scanner;
public class 最大最小公倍数 {
	static int end=0;
	static int N;
	static int[] a;
	//求三个数的最小公倍数
	static int fun(int[] a){
		int b=a[0],c=a[1],d=a[2];
		while(a[1]!=0){
			int temp=a[0]%a[1];
			a[0]=a[1];
			a[1]=temp;
		}
		//此时a[0]为最大公约数
		int sb=b*c/a[0];//a[0]和a[1]的最小公倍数
		int ssb=sb;
		while(a[2]!=0){
			int temp=sb%a[2];
			sb=a[2];
			a[2]=temp;
		}
		//此时sb为最大公约数
		int result=ssb*d/sb;
		return result;
	}
	//子集
	static void dfs(int[] x,int n,int i){
		if(i>n){//一个解,>n是对于数组长度为n+1的情况
			int count=0;
			a=new int[n+1];//重新清零
			for(int j=1;j<=N;j++){
				if(x[j]==1){
					a[count]=j;
					count++;
				}
			}
			if(count==3){//任意选出三个
				int result=fun(a);
				if(end<result){
					end=result;
				}
			}
		}
		else{
			x[i]=0;
			dfs(x,n,i+1);
			x[i]=1;
			dfs(x,n,i+1);
		}
	}

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        Scanner in=new Scanner(System.in);
        N=in.nextInt();
        int[] x=new int[N+1];
        dfs(x,N,1);
        System.out.println(end);
	}

}

7-9 猴子分苹果 (10分)

  秋天到了,n只猴子采摘了一大堆苹果放到山洞里,约定第二天平分。这些猴子很崇拜猴王孙悟空,所以都想给他留一些苹果。第一只猴子悄悄来到山洞,把苹果平均分成n份,把剩下的m个苹果吃了,然后藏起来一份,最后把剩下的苹果重新合在一起。这些猴子依次悄悄来到山洞,都做同样的操作,恰好每次都剩下了m个苹果。第二天,这些猴子来到山洞,把剩下的苹果分成n分,巧了,还是剩下了m个。问,原来这些猴子至少采了多少个苹果。

输入格式:

两个整数,n m

输出格式:

一个整数,表示原来苹果的数目

输入样例:

在这里给出一组输入。例如:

5 1

输出样例:

在这里给出相应的输出。例如:

15621

 思路:

小模拟,直接暴力,五个点,第一个点错,后俩超时。。

import java.util.Scanner;
public class 猴子分苹果 {
	static int n,m;
	static Boolean fun(int x){
		for(int i=0;i<n;i++){//第一天每只猴子的操作
			x-=m;
			if(x%n!=0){
				return false;
			}
			x-=(x/n);
		}
		//第二天
		if(x>n&&x%n==m){
			return true;
		}
		return false;
	}

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        Scanner in=new Scanner(System.in);
        n=in.nextInt();
        m=in.nextInt();
        if(n==0){
        	System.out.println(0);
        }
        for(int i=n;;i++){
        	if(fun(i)){
        		System.out.println(i);
        		return;
        	}
        }
	}

}

7-10 你究竟有几个好妹妹 (25分)

小李的QQ列表里有很多联系人,他修改了所有人的备注姓名。其中有些联系人名字的前部或后部被加了诸如"好妹妹"的字样。请你打印出小李的所有的女性"好妹妹"。打印时请按照联系人原始名字升序排列,如果两人名字相同则年龄小的排在前面;如果两人年龄相同,则较早成为好友的排在前面。题目保证好妹妹标志不会同时出现在前缀和后缀,同一天里也不会添加名字相同并且年龄相同的"好妹妹"。

输入格式:

第一行给出标识好妹妹标志的字符串,该字符串内不包含空格,最大长度为6并且不区分大小写。第二行给出QQ列表的所有联系人个数n (1≤ n ≤10​5​​),随后n行列出所有联系人信息,每行信息格式如下:

备注姓名 性别 年龄 结交好友日期

其中备注姓名不超过30个字符;性别用字符表示,F表示女性,M代表男性;结交好友日期采用诸如"2001.01.01"的格式表示。

输出格式:

第一行输出好妹妹的数目k,随后k行打印出去掉好妹妹标志的名字、年龄以及结交好友日期。

输入样例:

例如:

hmm
10
Zoehmm F 28 2001.01.01
hmmBeith F 18 2010.10.21
Zack M 35 1999.09.18
hmmAdam F 21 2010.10.21
Beithhmm F 21 2010.10.21
Chelse F 45 2005.12.03
DaisyHMM F 30 2008.08.05
Eston M 18 2015.03.04
hmmFrany F 8 2018.07.15
JackHM F 7 2017.09.11

输出样例:

输出:

6
Adam 21 2010.10.21
Beith 18 2010.10.21
Beith 21 2010.10.21
Daisy 30 2008.08.05
Frany 8 2018.07.15
Zoe 28 2001.01.01

思路

类排序继承Comparable接口)的一道题,没多大意思。

注意三点:

1.“好妹妹”标识不区分大小写,就把表示变成全小写,与备注姓名比较时也将相应字段变成小写方便比较。

2.将日期分割以‘.’时,要加转义字符\\

3.按原始姓名升序排列时,利用字符串compareTo函数即可,

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class 类排序_你究竟有几个好妹妹 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
        Scanner in=new Scanner(System.in);
        String mark=in.nextLine().toLowerCase();//不区分大小写,全变成小写
        int n=in.nextInt();
        Sister sis[]=new Sister[n];
        ArrayList<Sister> list=new ArrayList<Sister>();//存放好妹妹
        for(int i=0;i<n;i++){
        	sis[i]=new Sister();
        	sis[i].remark=in.next();
        	sis[i].sex=in.next();
        	if(sis[i].sex.equals("F")){//只有女的才有可能成为好妹妹
        		String front=sis[i].remark.substring(0, 3).toLowerCase(); 
        		String behind=sis[i].remark.substring(sis[i].remark.length()-3).toLowerCase();
        		if(front.equals(mark)){
            		sis[i].remark=sis[i].remark.substring(3);
            		list.add(sis[i]);
            	}
            	if(behind.equals(mark)){
            		sis[i].remark=sis[i].remark.substring(0, sis[i].remark.length()-3);
            		list.add(sis[i]);
            	}
        	}
        	sis[i].age=in.nextInt();
        	sis[i].date=in.next();
        	String[] str=sis[i].date.split("\\.");//'.'需要转义
        	sis[i].y=Integer.parseInt(str[0]);
        	sis[i].m=Integer.parseInt(str[1]);
        	sis[i].d=Integer.parseInt(str[2]);
        	//System.out.println(sis[i].remark+" "+sis[i].sex+" "+sis[i].age+" "+sis[i].date);
        }
        Sister hmm[]=new Sister[list.size()];
        for(int i=0;i<list.size();i++){
        	hmm[i]=list.get(i);
        }
        Arrays.sort(hmm);
        System.out.println(hmm.length);
        for(Sister s:hmm){
        	System.out.println(s.remark+" "+s.age+" "+s.date);
        }
        
	}

}
class Sister implements Comparable<Sister>{
	String remark;
	String sex;
	int age;
	String date;
	int y,m,d;
	@Override
	public int compareTo(Sister o) {
		// TODO 自动生成的方法存根
		if(this.remark.compareTo(o.remark)>0){		
			return 1;
		}
		else if(this.remark.compareTo(o.remark)<0){
			return -1;
		}
		else{//姓名一样
			if(this.age>o.age){
				return 1;
			}
			else if(this.age<o.age){
				return -1;
			}
			else{//年龄一样
				if(this.y>o.y){
					return 1;
				}
				else if(this.y<o.y){
					return -1;
				}
				else{
					if(this.m>o.m){
						return 1;
					}
					else if(this.m<o.m){
						return -1;
					}
					else{
						if(this.d>o.d){
							return 1;
						}
						else if(this.d<o.d){
							return -1;
						}
						else{
							return 0;
						}
					}
				}
			}
		}
		
	}
}
发布了81 篇原创文章 · 获赞 91 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44593822/article/details/103793701
1st