1. 程式人生 > 其它 >2021年第十二屆藍橋杯javaA組省賽部分題目

2021年第十二屆藍橋杯javaA組省賽部分題目

試題 D: 路徑

本題總分:10 分

【問題描述】
小藍學習了最短路徑之後特別高興,他定義了一個特別的圖,希望找到圖
中的最短路徑。
小藍的圖由 2021 個結點組成,依次編號 1 至 2021。
對於兩個不同的結點 a, b,如果 a 和 b 的差的絕對值大於 21,則兩個結點
之間沒有邊相連;如果 a 和 b 的差的絕對值小於等於 21,則兩個點之間有一條
長度為 a 和 b 的最小公倍數的無向邊相連。
例如:結點 1 和結點 23 之間沒有邊相連;結點 3 和結點 24 之間有一條無
向邊,長度為 24;結點 15 和結點 25 之間有一條無向邊,長度為 75。
請計算,結點 1 和結點 2021 之間的最短路徑長度是多少。
提示:建議使用計算機程式設計解決問題。

【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。

個人答案:10266837

解法1: 動態規劃,區間dp

import java.util.Arrays;

class Main{
	static int INF=0x3f3f3f3f;
	static int[][] dis=new int[2025][2025];
	public static void main(String[] args) {
		init();
		int n=2021;
		for(int len=2;len <= n;len++) {
			for(int i=1;i<= n-len+1;i++) {
				int j=i+len-1;
				for(int k=i;k<= j;k++) {
					dis[i][j]=Math.min(dis[i][j], dis[i][k]+dis[k][j]);
				}
			}
		}
		System.out.println(dis[1][n]);
	}
	private static void init() {
		// TODO Auto-generated method stub
		for(int i=0;i<2025;i++) {
			Arrays.fill(dis[i], INF);
		}
		for(int i=1;i<=2021;i++) {
			for(int j=1;j<=2021;j++) {
				if(Math.abs(i-j)>21) {
					continue;
				}else {
					dis[i][j]=dis[j][i]=Math.min(dis[i][j], gbs(i, j));
				}
			}
			dis[i][i]=0;
		}
	}
	private static int gbs(int a,int b) {
		// TODO Auto-generated method stub
		int at=a,bt=b;
		while(true) {
			int t=gcd(at, bt);
			if (t!=1) {
				at=at/t;
				bt=bt/t;
			}else {
				break;
			}
		}
		return at*b;
	}
	private static int gcd(int a,int b) {
		if (b==0) {
			return a;
		}
		return gcd(b, a%b);
	}
}

解法2:最短路演算法,這裡使用的是spfa

待補充

試題 E: 迴路計數

本題總分:15 分

【問題描述】
藍橋學院由 21 棟教學樓組成,教學樓編號 1 到 21。對於兩棟教學樓 a 和 b,當 a 和 b 互質時,a 和 b 之間有一條走廊直接相連,兩個方向皆可通行,否
則沒有直接連線的走廊。
小藍現在在第一棟教學樓,他想要訪問每棟教學樓正好一次,最終回到第
一棟教學樓(即走一條哈密爾頓迴路),請問他有多少種不同的訪問方案?兩個
訪問方案不同是指存在某個 i,小藍在兩個訪問方法中訪問完教學樓 i 後訪問了
不同的教學樓。
提示:建議使用計算機程式設計解決問題。

【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。

根據程式碼的意思:走 2 3 1和走 3 2 1算一種方法,因此才可以這樣用set儲存

個人答案:881012367360

方法1:dfs+減枝

本人直接使用dfs,跑一百年都跑不出來,。。。


import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 這種寫法要跑好幾秒才能得出結果
 * @author HQL
 */
public class _迴路計數 {
	static ArrayList<Integer>[] list;
	static Map<String, Long> set = new HashMap<String, Long>();
	public static void main(String[] args) {
		list = new ArrayList[21 + 1];
		for (int i = 0; i < list.length; ++i)
			list[i] = new ArrayList<Integer>();
		for (int i = 1; i <= 21; ++i)
			for (int j = i + 1; j <= 21; ++j)
				if (gcd(i, j) == 1) {
					list[i].add(j);
					list[j].add(i);
				}
		System.out.println(dfs(21, 1, 0));
	}
	public static long dfs(int total, int cur, int m) {
		if (total == 0)
			return 1;
		long res = 0;
		for (int p : list[cur]) {		
            //按位儲存,真的牛,這樣就可以儲存了
            //p為目標教學樓,m為當前已經訪問過的教學樓(
            //假設m==12,對應的二進位制為00001100,則m表示已經訪問過的教學樓有2、3號)
			if ((m & (1 << p)) != (1 << p)) {
				String pm = p + "-" + m;
				long r = 0;
				if (set.containsKey(pm)) {		//剪枝
					r = set.get(pm);
				} else {
					if (p != 1 || p == 1 && total == 1)
						r = dfs(total - 1, p, m | (1 << p));
					set.put(pm, r);
				}
				res += r;
			}
		}
		return res;
	}
	public static int gcd(int a, int b) {
		if (a == 0 || b == 0)
			return 0;
		return a % b == 0 ? b : gcd(b, a % b);
	}
}

方法2:狀態壓縮dp

不會。。。

試題 F: 最少砝碼

時間限制: 1.0s 記憶體限制: 512.0MB 本題總分:15 分

【問題描述】
你有一架天平。現在你要設計一套砝碼,使得利用這些砝碼可以稱出任意
小於等於 N 的正整數重量。
那麼這套砝碼最少需要包含多少個砝碼?
注意砝碼可以放在天平兩邊。

【輸入格式】
輸入包含一個正整數 N。

【輸出格式】
輸出一個整數代表答案。

【樣例輸入】
7

【樣例輸出】
3

【樣例說明】
3 個砝碼重量是 1、4、6,可以稱出 1 至 7 的所有重量。
1 = 1;
2 = 6 − 4 (天平一邊放 6,另一邊放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
少於 3 個砝碼不可能稱出 1 至 7 的所有重量。

【評測用例規模與約定】
對於所有評測用例,1 ≤ N ≤ 1000000000。

acwing中有這道題,找規律

試題 G: 左孩子右兄弟

時間限制: 3.0s 記憶體限制: 512.0MB 本題總分:20 分

【問題描述】
對於一棵多叉樹,我們可以通過 “左孩子右兄弟” 表示法,將其轉化成一棵二叉樹。如果我們認為每個結點的子結點是無序的,那麼得到的二叉樹可能不唯一。換句話說,每個結點可以選任意子結點作為左孩子,並按任意順序連線右兄弟。
給定一棵包含 N 個結點的多叉樹,結點從 1 至 N 編號,其中 1 號結點是根,每個結點的父結點的編號比自己的編號小。請你計算其通過 “左孩子右兄弟” 表示法轉化成的二叉樹,高度最高是多少。注:只有根結點這一個結點的樹高度為 0 。
例如如下的多叉樹:

可能有以下 3 種 (這裡只列出 3 種,並不是全部) 不同的 “左孩子右兄弟”
表示:

其中最後一種高度最高,為 4。

【輸入格式】
輸入的第一行包含一個整數 N。
以下 N −1 行,每行包含一個整數,依次表示 2 至 N 號結點的父結點編號。

【輸出格式】
輸出一個整數表示答案。

【樣例輸入】
5
1
1
1
2

【樣例輸出】
4

【評測用例規模與約定】
對於 30% 的評測用例,1 ≤ N ≤ 20;
對於所有評測用例,1 ≤ N ≤ 100000。

acwing上也是有這道題的。dfs搜尋即可

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

class Main{
	static int N=100000+5;
	static ArrayList<Integer>[] lists=new ArrayList[N];
	static long res=0L;
	public static void main(String[] args) throws IOException {
		init();
		BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
		String[] line=reader.readLine().split(" ");
		int n=Integer.parseInt(line[0]);
		for(int i=2;i<=n;i++) {
			line=reader.readLine().split(" ");
			int x=Integer.parseInt(line[0]);
			lists[x].add(i);
		}
		dfs(1,0);
		System.out.println(res);
	}
	private static void dfs(int cur, int len) {
		// TODO Auto-generated method stub
		if (lists[cur].size()==0) {
			res=Math.max(res, len);
			return;
		}
		int tonbei=lists[cur].size();
		for(int i=0;i<lists[cur].size();i++) {
			int son=lists[cur].get(i);
			dfs(son, len+tonbei);
		}
	}
	private static void init() {
		// TODO Auto-generated method stub
		for(int i=0;i<N;i++) {
			lists[i]=new ArrayList<Integer>();
		}
	}
}

來源: [https://blog.csdn.net/weixin_45640260/article/details/116377115]