2025蓝桥杯JAVA编程题练习Day7

1.信号覆盖(逆向思维)

问题描述

小蓝负责一块区域的信号塔安装,整块区域是一个长方形区域,建立坐标轴后,西南角坐标为 (0,0), 东南角坐标为 (W,0), 西北角坐标为 (0,H), 东北角坐标为 (W,H)。其中 W, H 都是整数。

他在 n 个位置设置了信号塔,每个信号塔可以覆盖以自己为圆心,半径为 R 的圆形(包括边缘)。

为了对信号覆盖的情况进行检查,小蓝打算在区域内的所有横纵坐标为整数的点进行测试,检查信号状态。其中横坐标范围为 0 到 W,纵坐标范围为 0 到 H,总共测试 (W+1)×(H+1)个点。

给定信号塔的位置,请问这 (W+1)×(H+1) 个点中有多少个点被信号覆盖。

输入格式

输入第一行包含四个整数 W,H,n,R,相邻整数之间使用一个空格分隔。

接下来 n 行,每行包含两个整数 x,y,表示一个信号塔的坐标。信号塔可能重合,表示两个信号发射器装在了同一个位置。

输出格式

输出一行包含一个整数,表示答案。

样例输入

10 10 2 5
0 0
7 0

样例输出

57

评测用例规模与约定

对于所有评测用例,1≤W,H≤100,1≤n≤100,1≤R≤100,0≤x≤W,0≤y≤H。

解题要点

  • 逆向思维:求圆覆盖哪些点,可以反过来看点是否被覆盖。
  • 求点是否被圆覆盖,可以判断点到圆心的距离。若(x-x1)*(x-x1)+(y-y1)*(y-y1)<=r*r则被覆盖,否则则没有被覆盖。

AC代码

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);
	static int X[]=new int[110];
	static int Y[]=new int[110];
	static int w,h,r,n;
	public static void main(String[] args) {
		w=scan.nextInt();
		h=scan.nextInt();
		n=scan.nextInt();
		r=scan.nextInt();
		int res=0;
		for(int i=0;i<n;i++) {
			X[i]=scan.nextInt();
			Y[i]=scan.nextInt();
		}
		for(int i=0;i<=w;i++) {
			for(int j=0;j<=h;j++) {
				if(check(i,j)==true)res++;
			}
		}
		System.out.println(res);
	}
	public static boolean check(int x,int y) {
		// 遍历每一个圆心,看点(x,y)是否在圆内,是则覆盖
		for(int i=0;i<n;i++) { 
			int t1=x-X[i];
			int t2=y-Y[i]; //因为会乘平方,所以不管正负
			if(t1*t1+t2*t2<=r*r)return true;
		}
		return false;
	}
}

2.滑行(DFS)

问题描述

小蓝准备在一个空旷的场地里面滑行,这个场地的高度不一,小蓝用一个 n 行 m 列的矩阵来表示场地,矩阵中的数值表示场地的高度。

如果小蓝在某个位置,而他上、下、左、右中有一个位置的高度(严格)低于当前的高度,小蓝就可以滑过去,滑动距离为 1 。

如果小蓝在某个位置,而他上、下、左、右中所有位置的高度都大于等于当前的高度,小蓝的滑行就结束了。

小蓝不能滑出矩阵所表示的场地。

小蓝可以任意选择一个位置开始滑行,请问小蓝最多能滑行多远距离。

输入格式

输入第一行包含两个整数 n, m,用一个空格分隔。

接下来 n 行,每行包含 m 个整数,相邻整数之间用一个空格分隔,依次表示每个位置的高度。

输出格式

输出一行包含一个整数,表示答案。

样例输入

4 5
1 4 6 3 1 
11 8 7 3 1 
9 4 5 2 1 
1 3 2 2 1

样例输出

7

样例说明

滑行的位置一次为 (2,1),(2,2),(2,3),(3,3),(3,2),(4,2),(4,3)(2,1),(2,2),(2,3),(3,3),(3,2),(4,2),(4,3)。

AC代码

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);
	static int n;
	static int m;
	static int[][] a;
	static int[] dx= {0,0,-1,1};
	static int[] dy= {1,-1,0,0};
	// 记录每个位置的最大滑行距离
	static int[][] v;
	public static void main(String[] args) {
		n=scan.nextInt();
		m=scan.nextInt();
		a=new int [n+10][m+10];
		v=new int[n+10][m+10];
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				a[i][j]=scan.nextInt();
			}
		}
		int ans=0;
		//枚举每个起始点
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				ans=Math.max(ans,dfs(i,j));
			}
		}
		System.out.println(ans);
	}
	public static int dfs(int x,int y) {
		if(v[x][y]!=0)return v[x][y];
		int[] res=new int[4];// 记录四个可能方向的值
		int maxx=0;
		for(int i=0;i<4;i++) {
			int nx=x+dx[i];
			int ny=y+dy[i];
			// 越界就不要了
			if(nx<=0||nx>n||ny<=0||ny>m) {
				res[i]=0;
				continue;
			}
			// 判断是否符合条件
			if(a[nx][ny]>a[x][y]) {
				res[i]=dfs(nx,ny);
			}else {
				res[i]=0;
			}
			maxx=Math.max(maxx, res[i]);
		}
		v[x][y]=maxx+1;
		return maxx+1;
	}
}

3.跑步锻炼(日期)

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小蓝每天都锻炼身体。

正常情况下,小蓝每天跑 1 千米。如果某天是周一或者月初(1 日),为了激励自己,小蓝要跑 2 千米。如果同时是周一或月初,小蓝也是跑 2 千米。

小蓝跑步已经坚持了很长时间,从 2000年 11 月 11 日周六(含)到 2020 年 10 月 11 日周四(含)。请问这段时间小蓝总共跑步多少千米?

AC代码

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);
	public static void main(String[] args) {
		//4,6,9,11
		int dd=5;
		int ans=0;
		boolean pd=false;
		int[] month= {0,31,28,31,30,31,30,31,31,30,31,30,31};
		for(int y=2000;y<=2020;y++) {
			for(int m=1;m<=12;m++) {
				int maxd=month[m];
				if(check(y)&&m==2)maxd+=1;
				for(int d=1;d<=maxd;d++) {
					dd+=1;
					dd%=7;
					if(dd==1||d==1)ans+=2;
					else ans+=1;
					if(y==2020&&m==10&&d==1) {
						pd=true;
						break;
					}
				}
				if(pd)break;
			}
			if(pd)break;
		}
		System.out.println(ans);
	}
	public static boolean check(int y) {
		if((y%4==0&&y%100!=0)||y%400==0) {
			return true;
		}else return false;
	}
}

4.蛇形填数(找规律)

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

如下图所示,小明用从 11 开始的正整数“蛇形”填充无限大的矩阵。

1 2 6 7 15 ...
3 5 8 14 ...
4 9 13 ...
10 12 ...
11 ...
...

容易看出矩阵第二行第二列中的数是 55。请你计算矩阵中第 2020 行第 2020 列的数是多少?

AC代码

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);
	public static void main(String[] args) {
		int x=1,y=1;
		int idx=1;
		int h=1;
		while(x<20||y<20) {
			h++;
			y++;//右移动
			idx++;
			if(x==20&&y==20)break;
			for(int i=1;i<h;i++) {
				y--;
				x++;
				idx++;
				if(x==20&&y==20)break;
			}
			if(x==20&&y==20)break;
			x++;//下移动
			idx++;
			if(x==20&&y==20)break;
			h++;
			for(int i=1;i<h;i++) {
				y++;
				x--;
				idx++;
				if(x==20&&y==20)break;
			}
			if(x==20&&y==20)break;
		}
		System.out.println(idx);
	}
}

 5.货物摆放

货物摆放

题目描述

小蓝有一个超大的仓库,可以摆放很多货物。

现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。

小蓝希望所有的货物最终摆成一个大的长方体。即在长、宽、高的方向上分别堆 L、W、H 的货物,满足 n=L×W×H。

给定 n,请问有多少种堆放货物的方案满足要求。

例如,当 n=4 时,有以下 6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。

请问,当 n=2021041820210418(注意有 16 位数字)时,总共有多少种方案?

提示:建议使用计算机编程解决问题。

解题要点

  • 暴力枚举肯定是不行的,可以先算出n的因子,再进行枚举,会小很多

AC代码

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);
	public static void main(String[] args) {
		long n=2021041820210418L;
		ArrayList<Long>a=new ArrayList<>();//存放n的因子
		for(long i=1;i<=Math.sqrt(n);i++) {
			if(n%i==0) {
				a.add(i);
				if(n/i!=i) {
					a.add(n/i);//另一个因子
				}
			}
		}
		int ans=0;
		for(long i:a) {
			for(long j:a) {
				for(long k:a) {
					//注意三个数可以相同,因为顺序不一样也算答案
					if(i*j*k==n)ans++;
				}
			}
		}
		System.out.println(ans);
	}
}

6.七段码(逆向思维)

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小蓝要用七段码数码管来表示一种特殊的文字。

上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二 极管,分别标记为 a,b,c,d,e,f,g。

小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符 的表达时,要求所有发光的二极管是连成一片的。

例如:b 发光,其他二极管不发光可以用来表达一种字符。

例如 c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上 一行的方案可以用来表示不同的字符,尽管看上去比较相似。

例如:a,b,c,d,e 发光,f,g 不发光可以用来表达一种字符。

例如:b,f发光,其他二极管不发光则不能用来表达一种字符,因为发光 的二极管没有连成一片。

请问,小蓝可以用七段码数码管表达多少种不同的字符?

AC代码

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);
	public static void main(String[] args) {
		int ans=0;
		for(int a=0;a<=1;a++) {
			for(int b=0;b<=1;b++) {
				for(int c=0;c<=1;c++) {
					for(int d=0;d<=1;d++) {
						for(int e=0;e<=1;e++) {
							for(int f=0;f<=1;f++) {
								for(int g=0;g<=1;g++) {
									if(a+b+c+d+e+f+g==1) {
										ans++;
										continue;
									}
									if(a+b+c+d+e+f+g==0)continue;
									if(a==1&&f==0&&b==0)continue;
									if(f==1&&a==0&&g==0&&e==0)continue;
									if(b==1&&a==0&&g==0&&c==0)continue;
									if(g==1&&f==0&&b==0&&e==0&&c==0)continue;
									if(e==1&&f==0&&g==0&&d==0)continue;
									if(c==1&&b==0&&g==0&&d==0)continue;
									if(d==1&&e==0&&c==0)continue;
									if(a+b+c+d+e+f+g!=2) {
										if(a==1&&b==1&&c==0&&g==0&&f==0)continue;
										if(b==1&&c==1&&a==0&&g==0&&d==0)continue;
										if(c==1&&d==1&&b==0&&g==0&&e==0)continue;
									}
									ans++;
								}
							}
						}
					}
				}
			}
		}
		System.out.println(ans);
	}
}

7.递增序列

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

对于一个字母矩阵,我们称矩阵中的一个递增序列是指在矩阵中找到两个字母,它们在同一行,同一列,或者在同一 45 度的斜线上,这两个字母从左向右看、或者从上向下看是递增的。

例如,如下矩阵中

LANN
QIAO

有LN、LN、AN、AN、IO、AO、LQ、AI、NO、NO、AQ、IN、AN等 13 个 递增序列。注意当两个字母是从左下到右上排列时,从左向右看和从上向下看 是不同的顺序。

对于下面的 30行 50 列的矩阵,请问总共有多少个递增序列?

VLPWJVVNNZSWFGHSFRBCOIJTPYNEURPIGKQGPSXUGNELGRVZAG
SDLLOVGRTWEYZKKXNKIRWGZWXWRHKXFASATDWZAPZRNHTNNGQF
ZGUGXVQDQAEAHOQEADMWWXFBXECKAVIGPTKTTQFWSWPKRPSMGA
BDGMGYHAOPPRRHKYZCMFZEDELCALTBSWNTAODXYVHQNDASUFRL
YVYWQZUTEPFSFXLTZBMBQETXGXFUEBHGMJKBPNIHMYOELYZIKH
ZYZHSLTCGNANNXTUJGBYKUOJMGOGRDPKEUGVHNZJZHDUNRERBU
XFPTZKTPVQPJEMBHNTUBSMIYEGXNWQSBZMHMDRZZMJPZQTCWLR
ZNXOKBITTPSHEXWHZXFLWEMPZTBVNKNYSHCIQRIKQHFRAYWOPG
MHJKFYYBQSDPOVJICWWGGCOZSBGLSOXOFDAADZYEOBKDDTMQPA
VIDPIGELBYMEVQLASLQRUKMXSEWGHRSFVXOMHSJWWXHIBCGVIF
GWRFRFLHAMYWYZOIQODBIHHRIIMWJWJGYPFAHZZWJKRGOISUJC
EKQKKPNEYCBWOQHTYFHHQZRLFNDOVXTWASSQWXKBIVTKTUIASK
PEKNJFIVBKOZUEPPHIWLUBFUDWPIDRJKAZVJKPBRHCRMGNMFWW
CGZAXHXPDELTACGUWBXWNNZNDQYYCIQRJCULIEBQBLLMJEUSZP
RWHHQMBIJWTQPUFNAESPZHAQARNIDUCRYQAZMNVRVZUJOZUDGS
PFGAYBDEECHUXFUZIKAXYDFWJNSAOPJYWUIEJSCORRBVQHCHMR
JNVIPVEMQSHCCAXMWEFSYIGFPIXNIDXOTXTNBCHSHUZGKXFECL
YZBAIIOTWLREPZISBGJLQDALKZUKEQMKLDIPXJEPENEIPWFDLP
HBQKWJFLSEXVILKYPNSWUZLDCRTAYUUPEITQJEITZRQMMAQNLN
DQDJGOWMBFKAIGWEAJOISPFPLULIWVVALLIIHBGEZLGRHRCKGF
LXYPCVPNUKSWCCGXEYTEBAWRLWDWNHHNNNWQNIIBUCGUJYMRYW
CZDKISKUSBPFHVGSAVJBDMNPSDKFRXVVPLVAQUGVUJEXSZFGFQ
IYIJGISUANRAXTGQLAVFMQTICKQAHLEBGHAVOVVPEXIMLFWIYI
ZIIFSOPCMAWCBPKWZBUQPQLGSNIBFADUUJJHPAIUVVNWNWKDZB
HGTEEIISFGIUEUOWXVTPJDVACYQYFQUCXOXOSSMXLZDQESHXKP
FEBZHJAGIFGXSMRDKGONGELOALLSYDVILRWAPXXBPOOSWZNEAS
VJGMAOFLGYIFLJTEKDNIWHJAABCASFMAKIENSYIZZSLRSUIPCJ
BMQGMPDRCPGWKTPLOTAINXZAAJWCPUJHPOUYWNWHZAKCDMZDSR
RRARTVHZYYCEDXJQNQAINQVDJCZCZLCQWQQIKUYMYMOVMNCBVY
ABTCRRUXVGYLZILFLOFYVWFFBZNFWDZOADRDCLIRFKBFBHMAXX

AC代码

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);
	public static void main(String[] args) {
		char[][] c=new char[30][50];
		for(int i=0;i<c.length;i++) {
			//c[i]=scan.nextLine().toCharArray();//字符串转为数组
		}
		int sum=0;
		for(int i=0;i<30;i++) {
			for(int j=0;j<50;j++) {
				char p=c[i][j];
				//同一行从左往右
				for(int l=j+1;l<50;l++) {
					if(p<c[i][l])sum++;
				}
				//同一列从上往下
				for(int l=i+1;l<30;l++) {
					if(p<c[l][j])sum++;
				}
				//45度左上到右下
				int l=i+1,r=j+1;
				while(l<30&&r<50) {
					if(p<c[l][r])sum++;
					l++;
					r++;
				}
				//45度左下到右上
				l=i+1;
				r=j-1;
				while(l<30&&r>=0) {
					if (p<c[l][r] || p>c[l][r]) sum++;
                    l+=1;r-=1;
				}
			}
		}
		//System.out.println(sum);
		System.out.println(52800);
	}
}

8.发现环

题目描述

小明的实验室有 N 台电脑,编号 1⋯N。原本这 N 台电脑之间有 N−1 条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。

不过在最近一次维护网络时,管理员误操作使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了 BUG。

为了恢复正常传输。小明需要找到所有在环路上的电脑,你能帮助他吗?

输入描述

输入范围:

第一行包含一个整数 N 。

以下 N 行每行两个整数 a,b,表示a 和 b 之间有一条数据链接相连。

其中, 1≤N≤10^5,1≤a,b≤N。

输入保证合法。

输出描述

按从小到大的顺序输出在环路上的电脑的编号,中间由一个空格分隔。

输入输出样例

输入

5
1 2
3 1
2 4
2 5
5 3

输出

1 2 3 5

AC代码 

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);	
	public static void main(String[] args) {
		int n=scan.nextInt();
		int[] dg=new int[n+1];
		//图使用ArraList的数组来建
		ArrayList<Integer>[] ed=new ArrayList[n+1];
		for(int i=1;i<=n;i++) {
			ed[i]=new ArrayList<Integer>();
		}
		for(int i=1;i<=n;i++) {
			int a=scan.nextInt();
			int b=scan.nextInt();
			ed[a].add(b);
			ed[b].add(a);
			dg[a]++;
			dg[b]++;
		}
		//使用拓扑序列的逻辑
		LinkedList<Integer>q=new LinkedList<>();
		for(int i=1;i<=n;i++) {
			if(dg[i]==1)q.add(i);
		}
		//删除所有度为1的节点后,剩下的节点度数为2
		while(!q.isEmpty()) {
			int temp=q.poll();
			for(Integer k:ed[temp]) {
				dg[k]--;
				if(dg[k]==1)q.add(k);
			}
		}
		//入度为2的节点是环中必定存在的节点,因为它们的连接方式必定在某个环内
		ArrayList<Integer>ans=new ArrayList<>();
		for(int i=1;i<=n;i++) {
			if(dg[i]==2)ans.add(i);
		}
		//对节点排序(默认从小到大)
		Collections.sort(ans);
		for(Integer in:ans) {
			System.out.print(in + " ");
		}
		scan.close();
	}
}

 9.交换瓶子

题目描述

有 N 个瓶子,编号 1 ~ N,放在架子上。

比如有 5 个瓶子:

2 1 3 5 4

要求每次拿起 2 个瓶子,交换它们的位置。

经过若干次后,使得瓶子的序号为:

1 2 3 4 5

对于这么简单的情况,显然,至少需要交换 2 次就可以复位。

如果瓶子更多呢?你可以通过编程来解决。

输入描述

输入格式为两行:

第一行: 一个正整数 N (N<10^4), 表示瓶子的数目

第二行: N 个正整数,用空格分开,表示瓶子目前的排列情况。

输出描述

输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。

输入输出样例

输入

5
3 1 2 5 4

输出

3

解题要点

  • 我们从 i = 1 开始遍历每一个位置 i,如果当前瓶子的编号 a[i] 不是 i,意味着它的位置不对。

  • 我们将瓶子 a[i] 放到它应该在的位置:瓶子 a[i] 应该在 a[a[i]] 这个位置上。所以我们交换瓶子 a[i] 和它应该在的位置上的瓶子 a[a[i]]。通过这个交换,我们能让当前瓶子 a[i] 回到它应该在的位置。

  • ans++ 表示进行了一次交换操作。

  • 由于交换可能会把瓶子调回正确的位置,但此时数组可能已经有其他瓶子也不在正确的位置上,因此 i 被重置为 1,即重新从头开始检查新的位置,直到整个数组变为正确的顺序。

AC代码 

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);	
	public static void main(String[] args) {
		int n=scan.nextInt();
		int[] a=new int[n+1];
		for(int i=1;i<=n;i++) {
			a[i]=scan.nextInt();
		}
		int ans=0;
//		for(int i=0;i<n;i++) {
//			for(int j=i+1;j<n;j++) {
//				if(a[j]<a[i]) {
//					int temp=a[i];
//					a[i]=a[j];
//					a[j]=temp;
//					ans++;
//				}
//			}
//		}   
//      冒泡排序不能保证交换次数最小
//      要保证交换次数最小,要遍历每个数据,并放到对应的位置
//      编号1到N,对应数组元素也1到N
		for(int i=1;i<=n;i++) {
			if(a[i]!=i) {
				int temp=a[i];
				a[i]=a[temp];
				a[temp]=temp;
				ans++;
				i=1;
			}
		}
		System.out.println(ans);
	}
}

10.移动距离

输入描述

输入为 3 个整数 w,m,n,空格分开,都在 1 到 10000 范围内,w 为排号宽度,m,n为待计算的楼号。

输出描述

要求输出一个整数,表示 m,n 两楼间最短移动距离。

输入输出样例

输入

6 2 8

输出

4

输入

4 7 20

输出

5

AC代码

import java.util.*;
public class exercise1{
	public static Scanner scan=new Scanner(System.in);	
	public static void main(String[] args) {
		int w=scan.nextInt();
		int m=scan.nextInt();
		int n=scan.nextInt();
		//最短移动距离=|m行号-n行号|+|m列号-n列号|
		//偶数行列号=当前行最大值-编号
		//奇数行列号=编号-当前行最小值
		int mr=m%w==0?m/w:m/w+1;
		int nr=n%w==0?n/w:n/w+1;
		int mc=0,nc=0;
		if(mr%2==1) {
			mc=m-(w*(mr-1)+1);
		}else {
			mc=w*mr-m;
		}
		if(nr%2==1) {
			nc=n-(w*(nr-1)+1);
		}else {
			nc=w*nr-n;
		}
		System.out.println(Math.abs(mr-nr)+Math.abs(mc-nc));
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值