倒计时5

博客围绕蓝桥杯真题展开,包含危险系数、愤怒小鸟、反幻方、打靶等问题。危险系数题需根据网络结构求两站点间关键点个数;反幻方要搜索三阶反幻方数量;还涉及递归等算法思路,以及图的深搜、全排列等信息技术知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题 1433: [蓝桥杯][2013年第四届真题]危险系数

时间限制: 1Sec 内存限制: 128MB 提交: 726 解决: 258

题目描述
问题描述
抗日战争时期,冀中平原的地道战曾发挥重要作用。
地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。
我们来定义一个危险系数DF(x,y):
对于两个站点x和y (x != y), 如果能找到一个站点z,当z被敌人破坏后,x和y不连通,那么我们称z为关于x,y的关键点。相应的,对于任意一对站点x和y,危险系数DF(x,y)就表示为这两点之间的关键点个数。
本题的任务是:已知网络结构,求两站点之间的危险系数。
输入
输入数据第一行包含2个整数n(2 < = n < = 1000), m(0 < = m < = 2000),分别代表站点数,通道数;
接下来m行,每行两个整数 u,v (1 < = u, v < = n; u != v)代表一条通道;
最后1行,两个数u,v,代表询问两点之间的危险系数DF(u, v)。
输出
一个整数,如果询问的两点不连通则输出-1.
样例输入
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
样例输出
2

思路:图 用矩阵表示,进行bfs,用cnt记录每个点被访问的次数
代码来自别人。我的代码错在 一开始没有考虑全面,导致后期添加记录每个点被访问的次数困难,这也是我的一个短板,但作为图的深搜,记录不同步骤,还是有参考意义的。
正确代码:

import java.util.ArrayList;
import java.util.Scanner;
 
public class 危险系数 {
	static boolean[] visited = null; // 用于记录该点是否为关键点
	static int[] cnt = null; // 用于统计该点已经走过几次
	static int[] way = null; // 用于记录路径
	static int ans = 0; // 路径总数
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(); // 站点数
		int m = sc.nextInt(); // 通道数 
		
		// 初始化三个数组
		visited = new boolean[n];
		way = new int[n];
		cnt = new int[n];
		// 用于记录通道
		ArrayList<Integer>[] stand = new ArrayList[n];
		for(int i = 0; i < n ; i++){
			stand[i] = new ArrayList<Integer>();
		}
		// 得到通道
		for(int i = 0 ; i < m; i++){
			int u = sc.nextInt() - 1;
			int v = sc.nextInt() - 1;
			stand[u].add(new Integer(v));
			stand[v].add(new Integer(u));
		}
		int a = sc.nextInt() - 1;
		int b = sc.nextInt() - 1;
		// 遍历通道
		DFS(a, b, stand, 0);
		// 获取结果
		System.out.println(GetResult());
	}
	/**
	 * 深度优先搜索通道
	 * @param start 当前节点
	 * @param end	末节点
	 * @param stand 通道集合
	 * @param k 当前是第几步
	 */
	public static void DFS(int start, int end, ArrayList<Integer>[] stand, int k){
		visited[start] = true; // 标记当前已经走过
		way[k] = start; // 第 k 步走了start这个点
		if(start == end){ // 当start等于结束这个点的时候,即找到了一条路径
			ans++; // 路径数目加一
			// 一共走了k步,注意:i < k 即没有把最后end这个点算在里面,最后结果不要算end这个点
			for(int i = 0; i < k; i++){
				cnt[way[i]]++; // 这条路径走过的点次数都加一
			}
			return;
		}
		// 深搜
		for(int i = 0; i < stand[start].size(); i++){
			int temp = stand[start].get(i).intValue();
			if(!visited[temp]){
				DFS(temp, end, stand, k + 1);
				visited[temp] = false;  // 还原点
			}
		}
	}
	public static int GetResult(){
		int sum = 0;;
		for(int i = 0; i < cnt.length; i++){
			if(cnt[i] == ans){ // 点出现的次数和路径个数相同,既每次都出现这个点,这个点为必须点
				sum++;
			}
		}
		return sum - 1; // 减去第一个点
	}
}

我的错误代码:

package day5;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;

public class t1433 {
	static HashMap<String, Boolean> hms=new HashMap<String, Boolean>();
	static int []vis;
	static int []count;
	static int m;
	static int n;
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		m=sc.nextInt();
		n=sc.nextInt();
		vis=new int[m];
		count=new int[m];
		int [][]num=new int[m][n];
		for(int i=0;i<n;i++){
			int x=sc.nextInt();
			int y=sc.nextInt();
			num[x-1][y-1]=1;
			num[y-1][x-1]=1;
		}
//		System.out.println("!!");
		int c1=sc.nextInt();
		int c2=sc.nextInt();
		
		bfs(num, c1-1, c1-1, c2-1, "");
		if(hms.size()==0){
			System.out.println("-1");
		}else{
//			System.out.println(hms.size());
			for(int i=0;i<m;i++){
				System.out.print(count[i]+" ");
			}
			count[c1-1]=-1;count[c2-1]=-1;
			Arrays.sort(count);
			
			System.out.println();
			int max_num=1;
			for(int i=m-2;i>=0;i--){
				if(count[i]==count[m-1]){
					max_num++;
				}
			}
			System.out.println(max_num);
		}
	}
	public static void bfs(int [][]num,int x,int y,int c2,String luj){
//		System.out.println(x+" "+y+" "+c2+" "+luj);
		if(y==c2&&num[x][y]==1){
			if(!hms.containsKey(luj)){
				hms.put(luj, true);
//				System.out.println(luj);
			}
//			System.out.println("ok!");
			return;
		}
		for(int i=y;i<num[0].length;i++){
			if(num[x][i]==1&&vis[i]==0){
				String s=luj+" "+x+" "+i;
				if(i==c2&&num[x][i]==1){
					if(!hms.containsKey(luj)){
						System.out.println(s);
						System.out.println("ok!");
						hms.put(luj, true);
						
//						vis[i]=1;
					}
					
//					System.out.println("ok!");
//					return;
				}
				
				
			}
		}
		vis[y]=1;
		count[y]++;
		for(int i=y;i<num[0].length;i++){
			if(num[x][i]==1&&vis[i]==0){
				String s=luj+" "+x+" "+i;
				vis[i]=1;
				count[i]++;
				bfs(num, i, 0, c2, s);
				vis[i]=0;
			}
		}
		
	}
//	public static void tongji(String s1,String s2){//统计两个字符串中,字符重复个数
//		String []ss1=s1.split(" ");
//		String []ss2=s2.split(" ");
//		int []num=new int [m];
//		for(int i=0;i<ss1.length;i++){
//			for(int j=0;j<ss2.length;i++){
//				if(ss1[i].equals(ss2[j])){
//					num[Integer.parseInt(ss1[i])]++;
//				}
//			}
//		}
//		for(int i=0;i<m;i++){
//			System.out.print(num[i]+" ");
//		}
//		syso
//		
//	}
}

二、愤怒小鸟
描述

X星球愤怒的小鸟喜欢撞火车!

一根平直的铁轨上两火车间相距 1000 米

两火车 (不妨称A和B) 以时速 10米/秒 相对行驶。

愤怒的小鸟从A车出发,时速50米/秒,撞向B车,

然后返回去撞A车,再返回去撞B车,如此往复…

两火车在相距1米处停车。

问:这期间愤怒的小鸟撞 B 车多少次?

注意:需要提交的是一个整数(表示撞B车的次数),不要填写任何其它内容。

输入
没有输入。

输出

package day3;

public class t1 {
    
    public static void main(String[] args) {  //PS:相对行驶,即面对面行驶
        double a=0,b=1000;
        while(b>=1){
        	//计算的d是碰撞之后,ab之间的距离
            b = b- 20 * (b/60);  //由a向b行驶,20是指两个火车速度和,60是鸟的速度+b车速度
            System.err.println(b+" "+1);
            b = b - 20 * (b/60);  //由b向a行驶,20是指两个火车速度和,60是鸟的速度+a车速度
            System.err.println(b+" "+2);
            a++;
        }
        System.out.println(a);
    }
}

二、反幻方
描述

我国古籍很早就记载着

2 9 4
7 5 3
6 1 8

这是一个三阶幻方。每行每列以及对角线上的数字相加都相等。

下面考虑一个相反的问题。

可不可以用 1~9 的数字填入九宫格。

使得:每行每列每个对角线上的数字和都互不相等呢?

这应该能做到。

比如:

9 1 2
8 4 3
7 5 6

你的任务是搜索所有的三阶反幻方。并统计出一共有多少种。

旋转或镜像算同一种。

比如:

9 1 2
8 4 3
7 5 6

7 8 9
5 4 1
6 3 2

2 1 9
3 4 8
6 5 7

等都算作同一种情况。

请提交三阶反幻方一共多少种。这是一个整数,不要填写任何多余内容。

输入
没有输入。

输出
控制台输出答案为一个整数。

思路:1-9全排列,判断是不是符合条件,利用HashSet存储,便于判断是反幻方,每个情况都是八种,再除以8

package day3;

import java.util.HashSet;

public class t2 {
	static int count = 0;
	public static void main(String[] args) {
		int []num={1,2,3,4,5,6,7,8,9};
		qpl(num, 0);
		System.out.println(count/8);
	}
	public static void qpl(int []num,int i){
		if(i==num.length){
//			for(int t=0;t<num.length;t++){
//				System.out.print(num[t]+" ");
//			}
//			System.out.println();
			jud(num);
		}else{
			for(int t=i;t<num.length;t++){
				swap(num, t, i);
				qpl(num, i+1);
				swap(num, t, i);
			}
		}
		
	}
	public static void jud(int []A){
		 int[] sum = new int[8];
	        sum[0] = A[0] + A[1] + A[2];
	        sum[1] = A[3] + A[4] + A[5];
	        sum[2] = A[6] + A[7] + A[8];
	        sum[3] = A[0] + A[3] + A[6];
	        sum[4] = A[1] + A[4] + A[7];
	        sum[5] = A[2] + A[5] + A[8];
	        sum[6] = A[0] + A[4] + A[8];
	        sum[7] = A[2] + A[4] + A[6];
	        HashSet<Integer> set = new HashSet<Integer>();
	        for(int i = 0;i < 8;i++)
	            set.add(sum[i]);
	        if(set.size() == 8)
	            count++;
	}
	public static void swap(int []num,int x,int y){
		int t=num[x];
		num[x]=num[y];
		num[y]=t;
	}
}

三、打靶
描述

小明参加X星球的打靶比赛。

比赛使用电子感应计分系统。其中有一局,小明得了96分。

这局小明共打了6发子弹,没有脱靶。

但望远镜看过去,只有3个弹孔。

显然,有些子弹准确地穿过了前边的弹孔。

不同环数得分是这样设置的:

1,2,3,5,10,20,25,50

那么小明的6发子弹得分都是多少呢?有哪些可能情况呢?

下面的程序解决了这个问题。

仔细阅读分析代码,填写划线部分缺失的内容。

输入
没有输入。

输出

思路: 这应该叫递归???对于填空处,如果这里打了孔,对于递归后,孔数就要减一

package day3;

public class t3
{	
	/**
	 * ta是判分
	 * da是
	 * k是
	 * ho 初始时3,即弹孔数
	 * bu 初始时6,即发射数
	 * sc初始是96,即得分数
	 * */
	static void f(int[] ta, int[] da, int k, int ho, int bu, int sc)
	{
		if(ho<0 || bu<0 || sc<0) return;
		if(k==ta.length){
			if(ho>0 || bu>0 || sc>0) return;
			for(int i=0; i<da.length; i++){
				for(int j=0; j<da[i]; j++) 
					System.out.print(ta[i] + "*");
			}
			System.out.println();
			return;
		}
		
		for(int i=0; i<=bu; i++){
			da[k] = i;
//			System.out.println(k+" "+da[k]);
			f(ta, da, k+1, ho - (i == 0 ? 0 : 1), bu-i, sc-ta[k]*i);   // 填空位置
		}
		
		da[k] = 0;
	}
	
	public static void main(String[] args)
	{
		int[] ta = {1,2,3,5,10,20,25,50};
		int[] da = new int[8];
		f(ta, da, 0, 3, 6, 96);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值