算法筆記_204:第四屆藍橋杯軟件類決賽真題(Java語言C組)
阿新 • • 發佈:2017-05-13
系統 主類 文字 新節點 origin pack log 破壞 src
目錄
1 好好學習
2 埃及分數
3 金蟬素數
4 橫向打印二叉樹
5 危險系數
6 公式求值
1 好好學習
湯姆跟爺爺來中國旅遊。一天,他幫助中國的小朋友貼標語。他負責貼的標語是分別寫在四塊紅紙上的四個大字:“好、好、學、習”。但是湯姆不認識漢字,他就想胡亂地貼成一行。 請你替小湯姆算一下,他這樣亂貼,恰好貼對的概率是多少? 答案是一個分數,請表示為兩個整數比值的形式。例如:1/3 或 2/15 等。 如果能夠約分,請輸出約分後的結果。 註意:不要書寫多余的空格。 請嚴格按照格式,通過瀏覽器提交答案。 註意:只提交這個比值,不要寫其它附加內容,比如:說明性的文字。1 / 12
2 埃及分數
古埃及曾經創造出燦爛的人類文明,他們的分數表示卻很令人不解。古埃及喜歡把一個分數分解為類似: 1/a + 1/b 的格式。 這裏,a 和 b 必須是不同的兩個整數,分子必須為 1 比如,2/15 一共有 4 種不同的分解法(姑且稱為埃及分解法): 1/8 + 1/120 1/9 + 1/45 1/10 + 1/30 1/12 + 1/20 那麽, 2/45 一共有多少個不同的埃及分解呢(滿足加法交換律的算同種分解)? 請直接提交該整數(千萬不要提交詳細的分解式!)。 請嚴格按照要求,通過瀏覽器提交答案。 註意:只提交分解的種類數,不要寫其它附加內容,比如:說明性的文字7
1 public class Main { 2 3 public static void main(String[] args) { 4 int count = 0; 5 for(int a = 1;a < 2000;a++) { 6 for(int b = 1;b < 2000;b++) { 7 if(45 * (a + b) == 2 * a * b) { 8 count++; 9 System.out.println("a = "+a+", b = "+b);10 } 11 } 12 } 13 System.out.println("count = "+count / 2); 14 } 15 }
3 金蟬素數
考古發現某古墓石碑上刻著一個數字:13597,後研究發現: 這是一個素數! 並且,去掉首尾數字仍是素數! 並且,最中間的數字也是素數! 這樣特征的數字還有哪些呢?通過以下程序的幫助可以輕松解決。請仔細閱讀代碼,並填寫劃線部分缺失的代碼。 public class A { static boolean isPrime(int n) { if(n<=1) return false; for(int i=2; i*i<=n; i++){ if(n%i==0) return false; } return true; } static void f(int[] x, int k) { if(_____________________________){ // 填空位置 if(isPrime(x[0]*10000 + x[1]*1000 + x[2]*100 + x[3]*10 + x[4]) && isPrime(x[1]*100 + x[2]*10 + x[3]) && isPrime(x[2])) System.out.println(""+x[0]+x[1]+x[2]+x[3]+x[4]); return; } for(int i=k; i<x.length; i++){ {int tmp=x[k]; x[k]=x[i]; x[i]=tmp; } f(x,k+1); {int tmp=x[k]; x[k]=x[i]; x[i]=tmp; } } } static void test() { int[] x = {1,3,5,7,9}; f(x,0); } public static void main(String[] args) { test(); } } 請分析代碼邏輯,並推測劃線處的代碼,通過網頁提交。 註意:僅把缺少的代碼作為答案,千萬不要填寫多余的代碼、符號或說明文字!! k == x.length
4 橫向打印二叉樹
二叉樹可以用於排序。其原理很簡單:對於一個排序二叉樹添加新節點時,先與根節點比較,若小則交給左子樹繼續處理,否則交給右子樹。 當遇到空子樹時,則把該節點放入那個位置。 比如,10 8 5 7 12 4 的輸入順序,應該建成二叉樹如圖1所示。 本題目要求:根據已知的數字,建立排序二叉樹,並在標準輸出中橫向打印該二叉樹。 輸入數據為一行空格分開的N個整數。 N<100,每個數字不超過10000。 輸入數據中沒有重復的數字。 輸出該排序二叉樹的橫向表示。 對應上例中的數據,應輸出: |-12 10-| |-8-| | |-7 |-5-| |-4 為了便於評卷程序比對空格的數目,請把空格用句點代替: ...|-12 10-| ...|-8-| .......|...|-7 .......|-5-| ...........|-4 例如: 用戶輸入: 10 5 20 則程序輸出: ...|-20 10-| ...|-5 再例如: 用戶輸入: 5 10 20 8 4 7 則程序輸出: .......|-20 ..|-10-| ..|....|-8-| ..|........|-7 5-| ..|-4 資源約定: 峰值內存消耗(含虛擬機) < 64M CPU消耗 < 1000ms 請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。 所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。 註意:不要使用package語句。不要使用jdk1.6及以上版本的特性。 註意:主類的名字必須是:Main,否則按無效代碼處理。
1 import java.util.Scanner; 2 3 public class Main { 4 public static int begin; 5 6 static class Tree { 7 public int value; 8 public int left; 9 public int right; 10 11 public Tree(int value, int left, int right) { 12 this.value = value; 13 this.left = left; 14 this.right = right; 15 } 16 } 17 18 public void dfs(int start, Tree[] tree, String s1, String s2, int n) { 19 if(start == begin) 20 s1 = s1 + tree[start].value; 21 else { 22 s1 = s1 + "-|-"; 23 s1 = s1 + tree[start].value; 24 } 25 if(tree[start].right != -1) { 26 s2 = s2 + "1"; 27 dfs(tree[start].right, tree, s1, s2, n + 1); 28 s2 = s2.substring(0, s2.length() - 1); 29 } 30 int t = 0; 31 for(int i = 0;i < s1.length();i++) { 32 if(s1.charAt(i) == ‘|‘) { 33 if(s2.length() <= t + 1 || s2.charAt(t) != s2.charAt(t + 1)) 34 System.out.print("|"); 35 else 36 System.out.print("."); 37 t++; 38 } else if(t < n) { 39 System.out.print("."); 40 } else 41 System.out.print(s1.charAt(i)); 42 } 43 if(tree[start].left != -1 || tree[start].right != -1) 44 System.out.print("-|"); 45 System.out.println(); 46 if(tree[start].left != -1) { 47 s2 = s2 + "0"; 48 dfs(tree[start].left, tree, s1, s2, n + 1); 49 s2 = s2.substring(0, s2.length() - 1); 50 } 51 } 52 53 public static void main(String[] args) { 54 Main test = new Main(); 55 Scanner in = new Scanner(System.in); 56 String A = in.nextLine(); 57 String[] arrayA = A.split(" "); 58 Tree[] tree = new Tree[10005]; 59 for(int i = 0;i < arrayA.length;i++) { 60 int v = Integer.valueOf(arrayA[i]); 61 tree[v] = new Tree(v, -1, -1); 62 } 63 int start = Integer.valueOf(arrayA[0]); 64 begin = start; 65 for(int i = 1;i < arrayA.length;i++) { 66 int v = Integer.valueOf(arrayA[i]); 67 int temp = start; 68 while(true) { 69 if(v > temp) { 70 if(tree[temp].right == -1) { 71 tree[temp].right = v; 72 break; 73 } else 74 temp = tree[temp].right; 75 } else { 76 if(tree[temp].left == -1) { 77 tree[temp].left = v; 78 break; 79 } else 80 temp = tree[temp].left; 81 } 82 } 83 } 84 String s1 = ""; 85 String s2 = ""; 86 test.dfs(start, tree, s1, s2, 0); 87 } 88 }
5 危險系數
抗日戰爭時期,冀中平原的地道戰曾發揮重要作用。 地道的多個站點間有通道連接,形成了龐大的網絡。但也有隱患,當敵人發現了某個站點後,其它站點間可能因此會失去聯系。 我們來定義一個危險系數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 資源約定: 峰值內存消耗(含虛擬機) < 64M CPU消耗 < 2000ms 請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。 所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。 註意:不要使用package語句。不要使用jdk1.6及以上版本的特性。 註意:主類的名字必須是:Main,否則按無效代碼處理。
1 import java.util.ArrayList; 2 import java.util.Scanner; 3 4 public class Main { 5 public static int n, m, start, end; 6 public static ArrayList<Integer>[] map; 7 public static int count, root; 8 public static int[] DFN; 9 public static int[] Low; 10 public static int[] Parent; 11 public ArrayList<Integer> point; 12 13 public void init() { 14 count = 0; 15 root = 1; 16 DFN = new int[n + 1]; 17 Low = new int[n + 1]; 18 Parent = new int[n + 1]; 19 point = new ArrayList<Integer>(); 20 for(int i = 1;i <= n;i++) { 21 DFN[i] = -1; 22 Low[i] = -1; 23 Parent[i] = -1; 24 } 25 } 26 27 public void TarJan(int begin, int parent) { 28 DFN[begin] = ++count; 29 Low[begin] = DFN[begin]; 30 Parent[begin] = parent; 31 int Childern = 0; 32 for(int i = 0;i < map[begin].size();i++) { 33 int j = map[begin].get(i); 34 if(DFN[j] == -1) { 35 Childern++; 36 TarJan(j, begin); 37 Low[begin] = Math.min(Low[begin], Low[j]); 38 if(begin == root && Childern > 1) { 39 if(!point.contains(begin)) 40 point.add(begin); 41 } else if(begin != root && Low[j] >= DFN[begin]) { 42 if(!point.contains(begin)) 43 point.add(begin); 44 } 45 } else if(j != Parent[begin]) { 46 Low[begin] = Math.min(Low[begin], DFN[j]); 47 } 48 } 49 } 50 51 public void dfs(int begin, boolean[] visited) { 52 visited[begin] = true; 53 for(int i = 0;i < map[begin].size();i++) { 54 int j = map[begin].get(i); 55 if(visited[j] == false) 56 dfs(j, visited); 57 } 58 } 59 60 public void getResult() { 61 boolean[] visited = new boolean[n + 1]; 62 dfs(start, visited); 63 if(visited[end] == false) { 64 System.out.println("-1"); 65 return; 66 } 67 init(); 68 TarJan(1, 0); 69 int count = 0; 70 for(int i = 0;i < point.size();i++) { 71 int j = point.get(i); 72 if(j != start && j != end) { 73 visited = new boolean[n + 1]; 74 visited[j] = true; 75 dfs(start, visited); 76 if(visited[end] == false) 77 count++; 78 } 79 } 80 System.out.println(count); 81 } 82 83 @SuppressWarnings("unchecked") 84 public static void main(String[] args) { 85 Main test = new Main(); 86 Scanner in = new Scanner(System.in); 87 n = in.nextInt(); 88 m = in.nextInt(); 89 map = new ArrayList[n + 1]; 90 for(int i = 1;i <= n;i++) 91 map[i] = new ArrayList<Integer>(); 92 for(int i = 1;i <= m;i++) { 93 int u = in.nextInt(); 94 int v = in.nextInt(); 95 map[u].add(v); 96 map[v].add(u); 97 } 98 start = in.nextInt(); 99 end = in.nextInt(); 100 test.getResult(); 101 } 102 }
6 公式求值
6、標題:公式求值 輸入n, m, k,輸出圖1所示的公式的值。其中C_n^m是組合數,表示在n個人的集合中選出m個人組成一個集合的方案數。組合數的計算公式如圖2所示。 輸入的第一行包含一個整數n;第二行包含一個整數m,第三行包含一個整數k。 計算圖1所示的公式的值,由於答案非常大,請輸出這個值除以999101的余數。 【樣例輸入1】 3 1 3 【樣例輸出1】 162 【樣例輸入2】 20 10 10 【樣例輸出2】 359316 【數據規模與約定】 對於10%的數據,n≤10,k≤3; 對於20%的數據,n≤20,k≤3; 對於30%的數據,n≤1000,k≤5; 對於40%的數據,n≤10^7,k≤10; 對於60%的數據,n≤10^15,k ≤100; 對於70%的數據,n≤10^100,k≤200; 對於80%的數據,n≤10^500,k ≤500; 對於100%的數據,n在十進制下不超過1000位,即1≤n<10^1000,1≤k≤1000,同時0≤m≤n,k≤n。 【提示】 999101是一個質數; 當n位數比較多時,絕大多數情況下答案都是0,但評測的時候會選取一些答案不是0的數據; 資源約定: 峰值內存消耗(含虛擬機) < 128M CPU消耗 < 2000ms 請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。 所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。 註意:不要使用package語句。不要使用jdk1.6及以上版本的特性。 註意:主類的名字必須是:Main,否則按無效代碼處理。
完整解答請參見: 公式求值 解題報告
下面是樓主自己使用蠻力法求解,只過藍橋練習系統中3組數據>~<。
1 import java.math.BigInteger; 2 import java.util.Scanner; 3 4 public class Main { 5 6 public BigInteger getCnm(long n, long m) { 7 BigInteger A = BigInteger.ONE; 8 BigInteger B = BigInteger.ONE; 9 long c = m; 10 if(n-m > m) 11 c = n - m; 12 for(long i = c + 1;i <= n;i++) 13 A = A.multiply(new BigInteger(""+i)); 14 for(long i = 1;i <= n - c;i++) 15 B = B.multiply(new BigInteger(""+i)); 16 return A.divide(B); 17 } 18 19 public BigInteger getXk(long a, long b) { 20 BigInteger temp = new BigInteger(""+a); 21 BigInteger result = BigInteger.ONE; 22 while(b != 0) { 23 if((b&1) == 1) 24 result = result.multiply(temp); 25 temp = temp.multiply(temp); 26 b >>= 1; 27 } 28 return result; 29 } 30 31 public void getReuslt(long n, long m, int k) { 32 BigInteger result = getCnm(n, m); 33 BigInteger sum = BigInteger.ZERO; 34 for(long i = 0;i <= n;i++) 35 sum = sum.add(getCnm(n, i).multiply(getXk(i, k))); 36 result = result.multiply(sum).mod(new BigInteger("999101")); 37 System.out.println(result); 38 } 39 40 public static void main(String[] args) { 41 Main test = new Main(); 42 Scanner in = new Scanner(System.in); 43 long n = in.nextLong(); 44 long m = in.nextLong(); 45 int k = in.nextInt(); 46 test.getReuslt(n, m, k); 47 } 48 }
算法筆記_204:第四屆藍橋杯軟件類決賽真題(Java語言C組)