算法筆記_206:第五屆藍橋杯軟件類決賽真題(Java語言A組)
阿新 • • 發佈:2017-05-15
理論 cnblogs 條件 font 9.png 生成 true 突變 幻方
目錄
1 海盜分金幣
2 六角幻方
3 格子放雞蛋
4 排列序數
5 冪一矩陣
6 供水設施
1 海盜分金幣
有5個海盜,相約進行一次帆船比賽。 比賽中天氣發生突變,他們被沖散了。 恰巧,他們都先後經過途中的一個無名的荒島,並且每個人都信心滿滿,覺得自己是第一個經過該島的人。 第一個人在沙灘上發現了一堆金幣。他把金幣分成5等份。發現剛好少一個金幣。他就從自己口袋拿出一個金幣補充進去,然後把屬於自己的那份拿走。 第二個到達的人也看到了金幣,他也和第一個人一樣,把所有金幣5等分,發現剛好缺少一個金幣,於是自己補進去一個,拿走了屬於自己的那份。 第三,第四,第五人的情況一模一樣。 等他們到了目的地,都說自己的情況,才恍然大悟,一起去荒島找金幣,然而再也沒有找到荒島。他們都惋惜地說:島上還有一千多枚金幣呢! 請你根據這些信息,推算荒島上最初有多少金幣? 這是一個整數,請通過瀏覽器提交答案,不要填寫任何多余的內容(比如說明性的文字等)3129
1 public class Main { 2 3 public static void main(String[] args) { 4 for(int i = 1000;i < 100000;i++) { 5 int a1, a2, a3, a4, a5; 6 if((i + 1) % 5 != 0) 7 continue; 8 a1 = (i + 1) / 5 - 1; 9 if((i - a1 + 1) % 5 != 0)10 continue; 11 a2 = (i - a1 + 1) / 5 - 1; 12 if((i - a1 - a2 + 1) % 5 != 0) 13 continue; 14 a3 = (i - a1 - a2 + 1) / 5 - 1; 15 if((i - a1 - a2 - a3 + 1) % 5 != 0) 16 continue; 17 a4 = (i - a1 - a2 - a3 + 1) / 5 - 1;18 if((i - a1 - a2 - a3 - a4 + 1) % 5 != 0) 19 continue; 20 a5 = (i - a1 - a2 - a3 - a4 + 1) / 5 - 1; 21 int temp = i - a1 - a2 - a3 - a4 - a5; 22 if(temp > 1000 && temp < 2000) 23 System.out.println("i = "+i); 24 } 25 } 26 }
2 六角幻方
把 1 2 3 ... 19 共19個整數排列成六角形狀,如下: * * * * * * * * * * * * * * * * * * * 要求每個直線上的數字之和必須相等。共有15條直線哦! 再給點線索吧!我們預先填好了2個數字,第一行的頭兩個數字是:15 13,參見圖【p1.png】,黃色一行為所求。 請你填寫出中間一行的5個數字。數字間用空格分開。 這是一行用空格分開的整數,請通過瀏覽器提交答案,不要填寫任何多余的內容(比如說明性的文字等) 9 6 5 2 16
1 public class Main { 2 public static boolean[] used = new boolean[20]; 3 4 public void swap(int[] A, int i, int j) { 5 int temp = A[i]; 6 A[i] = A[j]; 7 A[j] = temp; 8 } 9 10 public boolean check(int[] A, int step) { 11 int sum = A[0] + A[1] + A[2]; 12 if(step >= 7) { 13 if(A[3] + A[4] + A[5] + A[6] != sum) 14 return false; 15 } 16 if(step >= 8) 17 if(A[0] + A[3] + A[7] != sum) 18 return false; 19 if(step >= 12) { 20 if(A[7] + A[8] + A[9] + A[10] + A[11] != sum) 21 return false; 22 if(A[2] + A[6] + A[11] != sum) 23 return false; 24 } 25 if(step >= 13) 26 if(A[1] + A[4] + A[8] + A[12] != sum) 27 return false; 28 if(step >= 16) { 29 if(A[12] + A[13] + A[14] + A[15] != sum) 30 return false; 31 if(A[1] + A[5] + A[10] + A[15] != sum) 32 return false; 33 } 34 if(step >= 17) { 35 if(A[2] + A[5] + A[9] + A[13] + A[16] != sum || A[7]+A[12]+A[16] != sum) 36 return false; 37 } 38 if(step >= 18) 39 if(A[3] + A[8] + A[13] + A[17] != sum || A[6] + A[10] + A[14] + A[17] != sum) 40 return false; 41 if(step >= 19) { 42 if(A[0]+A[4]+A[9]+A[14]+A[18] != sum || A[16] + A[17] + A[18] != sum || A[11] + A[15] + A[18] != sum) 43 return false; 44 } 45 return true; 46 } 47 48 public void dfs(int[] A, int step) { 49 if(check(A, step) == false) 50 return; 51 if(step == 19) { 52 for(int i = 0;i < A.length;i++) 53 System.out.print(A[i]+" "); 54 System.out.println(); 55 return; 56 } 57 for(int i = 1;i <= 19;i++) { 58 if(used[i] == false) { 59 used[i] = true; 60 A[step] = i; 61 dfs(A, step + 1); 62 used[i] = false; 63 } 64 } 65 66 } 67 68 public static void main(String[] args) { 69 Main test = new Main(); 70 int[] A = new int[19]; 71 A[0] = 15; 72 A[1] = 13; 73 A[2] = 10; 74 used[15] = true; 75 used[13] = true; 76 used[10] = true; 77 test.dfs(A, 3); 78 } 79 }
3 格子放雞蛋
X星球的母雞很聰明。它們把蛋直接下在一個 N * N 的格子中,每個格子只能容納一枚雞蛋。它們有個習慣,要求:每行,每列,以及每個斜線上都不能有超過2個雞蛋。如果要滿足這些要求,母雞最多能下多少蛋呢,有多少種擺放方法呢? 下面的程序解決了這個問題,請仔細分析程序邏輯,推斷劃線處缺少的代碼。 public class A { static int max = 0; static int T = 0; static final int N = 6; // 只能在(r,c) 以及其右,其下放置 static void f(int[][] da, int r, int c) { if(r>=N){ int n = count(da); if(n>max) { max = n; T = 0; } if(n==max) T++; return; } //計算一下步放哪 int r_next = r; int c_next = c + 1; if(c_next>=N){ c_next = 0; r_next++; } if(____________________){ // 填空位置 da[r][c] = 1; f(da, r_next, c_next); } da[r][c] = 0; f(da, r_next, c_next); } static int count(int[][] da) { int n = 0; for(int i=0; i<da.length; i++) for(int j=0; j<da[i].length; j++) if(da[i][j]==1) n++; return n; } static int spy(int[][] da, int r, int c) { int m=0; // 該行 int n=0; for(int i=0; i<N; i++) if(da[r][i]==1) n++; if(n>m) m = n; //該列 n=0; for(int i=0; i<N; i++) if(da[i][c]==1) n++; if(n>m) m = n; //右斜線 n=0; for(int i=0; i<N; i++){ if(r-i<0 || c-i<0) break; if(da[r-i][c-i]==1) n++; } for(int i=1; i<N; i++){ if(r+i>=N || c+i>=N) break; if(da[r+i][c+i]==1) n++; } if(n>m) m = n; //左斜線 n=0; for(int i=0; i<N; i++){ if(r-i<0 || c+i>=N) break; if(da[r-i][c+i]==1) n++; } for(int i=1; i<N; i++){ if(r+i>=N || c-i<0) break; if(da[r+i][c-i]==1) n++; } if(n > m) m = n; return m; } public static void main(String[] args) { int[][] da = new int[N][N]; f(da, 0, 0); System.out.println(max); System.out.println(T); } } 註意:通過瀏覽器提交答案。只填寫缺少的內容,不要填寫任何多余的內容(例如:說明性文字或已有符號)。 spy(da, r, c) < 2
4 排列序數
如果用a b c d這4個字母組成一個串,有4!=24種,如果把它們排個序,每個串都對應一個序號: abcd 0 abdc 1 acbd 2 acdb 3 adbc 4 adcb 5 bacd 6 badc 7 bcad 8 bcda 9 bdac 10 bdca 11 cabd 12 cadb 13 cbad 14 cbda 15 cdab 16 cdba 17 ... 現在有不多於10個兩兩不同的小寫字母,給出它們組成的串,你能求出該串在所有排列中的序號嗎? 【輸入格式】 一行,一個串。 【輸出格式】 一行,一個整數,表示該串在其字母所有排列生成的串中的序號。註意:最小的序號是0。 例如: 輸入: bdca 程序應該輸出: 11 再例如: 輸入: cedab 程序應該輸出: 70 資源約定: 峰值內存消耗(含虛擬機) < 256M CPU消耗 < 1000ms 請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。 所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。 註意:不要使用package語句。不要使用jdk1.7及以上版本的特性。 註意:主類的名字必須是:Main,否則按無效代碼處理。
1 import java.util.Arrays; 2 import java.util.Scanner; 3 4 public class Main { 5 public static char[] arrayA; 6 7 //返回n!= 1*2*3*...*n 8 public long getN(int n) { 9 long result = 1; 10 for(int i = 1;i <= n;i++) 11 result = result * i; 12 return result; 13 } 14 15 public void getResult(String A) { 16 int len = A.length(); 17 arrayA = A.toCharArray(); 18 Arrays.sort(arrayA); 19 boolean[] used = new boolean[len]; 20 long count = 0; 21 for(int i = 0;i < len;i++) { 22 char t = A.charAt(i); 23 int a = 0; 24 for(int j = 0;j < len;j++) { 25 if(used[j] == true) 26 continue; 27 if(arrayA[j] == t) { 28 used[j] = true; 29 break; 30 } 31 a++; 32 } 33 count = count + a * getN(len - 1 - i); 34 } 35 System.out.println(count); 36 } 37 38 public static void main(String[] args) { 39 Main test = new Main(); 40 Scanner in = new Scanner(System.in); 41 String A = in.next(); 42 test.getResult(A); 43 } 44 }
5 冪一矩陣
天才少年的鄰居 atm 最近學習了線性代數相關的理論,他對“矩陣”這個概念特別感興趣。矩陣中有個概念叫做冪零矩陣。對於一個方陣 M ,如果存在一個正整數 k 滿足 M^k = 0 ,那麽 M 就是一個冪零矩陣。(^ 表示乘方) atm 不滿足冪零矩陣,他自己設想了一個冪一矩陣:對於一個方陣 M ,如果存在一個正整數 k 滿足 M^k = I ,其中 I 是單位矩陣,那麽 M 就是一個冪一矩陣。 atm 特別鐘情於這樣一種方陣:每行每列有且僅有一個 1 。經過 atm 不斷實驗,他發現這種矩陣都是冪一矩陣。 現在,他的問題是,給定一個滿足以上條件的方陣,他想求最小的 k 是多少。 【輸入格式】 第一行一個正整數 n ,表示矩陣大小是 n * n 。 接下來 n 行,每行兩個正整數 i j 表示方陣的第 i 行第 j 列為 1。 1 <= i, j <= n 。 行號,列號都從1開始。 【輸出格式】 一行。一個正整數,即題目中所說最小的 k 。 【樣例輸入】 5 3 1 1 2 4 4 2 3 5 5 【樣例輸出】 3 【數據範圍】 對於 30% 的數據滿足 n <= 10 對於 60% 的數據答案不超過 10^18 對於 100% 的數據滿足 n <= 10000 資源約定: 峰值內存消耗(含虛擬機) < 256M CPU消耗 < 1000ms 請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。 所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。 註意:不要使用package語句。不要使用jdk1.7及以上版本的特性。 註意:主類的名字必須是:Main,否則按無效代碼處理。
正解請參見: 冪一矩陣——詳解第五屆藍橋杯決賽題目
以下是樓主自己使用暴力求解,只能過部分數據>~<
1 import java.util.Scanner; 2 3 public class Main { 4 5 public int[][] multiMatrix(int[][] A, int[][] B) { 6 int ring = A.length; 7 int row = B[0].length; 8 int[][] result = new int[ring][row]; 9 for(int i = 0;i < A.length;i++) 10 for(int j = 0;j < B[0].length;j++) 11 for(int k = 0;k < A[0].length;k++) 12 result[i][j] += A[i][k] * B[k][j]; 13 return result; 14 } 15 16 public void getResult(int[][] M) { 17 int k = 1; 18 int[][] R = new int[M.length][M[0].length]; 19 for(int i = 0;i < M.length;i++) 20 for(int j = 0;j < M[0].length;j++) 21 R[i][j] = M[i][j]; 22 while(true) { 23 boolean judge = true; 24 for(int i = 0;i < M.length;i++) { 25 if(judge == false) 26 break; 27 for(int j = 0;j < M[0].length;j++) { 28 if(i == j && R[i][j] == 0) { 29 judge = false; 30 break; 31 } 32 else if(i != j && R[i][j] == 1) { 33 judge = false; 34 break; 35 } 36 } 37 } 38 if(judge == true) 39 break; 40 R = multiMatrix(R, M); 41 k++; 42 } 43 System.out.println(k); 44 } 45 46 public static void main(String[] args) { 47 Main test = new Main(); 48 Scanner in = new Scanner(System.in); 49 int n = in.nextInt(); 50 int[][] M = new int[n][n]; 51 for(int i = 0;i < n;i++) { 52 int a = in.nextInt(); 53 int b = in.nextInt(); 54 M[a - 1][b - 1] = 1; 55 } 56 test.getResult(M); 57 } 58 }
6 供水設施
X星球的居民點很多。Pear決定修建一個浩大的水利工程,以解決他管轄的N個居民點的供水問題。現在一共有N個水塔,同時也有N個居民點,居民點在北側從1號到N號自西向東排成一排;水塔在南側也從1號到N號自西向東排成一排。 N條單向輸水線(有水泵動力),將水從南側的水塔引到北側對應的居民點。 我們不妨將居民點和水塔都看做平面上的點,居民點坐標為(1,K)~(N,K),水塔為(1,0)~(N,0)。 除了N條縱向輸水線以外,還有M條單向的橫向輸水線,連接(Xi,Yi)和(Xi,(Yi)+1)或者(Xi,Yi)和(Xi,(Yi)-1)。前者被稱為向右的水路,而後者是向左的。不會有兩條水路重疊,即便它們方向不同。 布局的示意圖如:【p1.png】所示。 顯然,每個水塔的水都可以到達若幹個居民點(而不僅僅是對應的那個)。例如上圖中,4號水塔可以到達3、4、5、6四個居民點。 現在Pear決定在此基礎上,再修建一條橫向單項輸水線。為了方便考慮,Pear認為這條水路應當是自左向右的,也就是連接了一個點和它右側的點(例如上圖中連接5和6兩個縱線的橫向水路)。 Pear的目標是,修建了這條水路之後,能有盡可能多對水塔和居民點之間能到達。換句話說,設修建之後第i個水塔能到達Ai個點,你要最大化A1+A2+...+An。 根據定義,這條路必須和X軸平行,但Y坐標不一定要是整數。註意:雖然輸入中沒有重疊的水路,但是你的方案可以將新修的輸水線路與已有的水路重疊。 【輸入數據】 輸入第一行包含三個正整數N,M,K,含義如題面所述:N是縱向線數,M橫向線數,K是居民點縱坐標。 接下來M行,每行三個整數。前兩個正整數Xi Yi表示水路的起點坐標; 1<=Xi<=N,0<Yi<K。 接下來一個數0或者1,如果是0表示這條水路向左,否則向右。 保證水路都是合法的,也就是不會流向沒有定義的地方。 【輸出數據】 輸出一行。是一個正整數,即:題目中要求的最大化的A1+A2+...+An。 【輸入樣例1】 4 3 2 1 1 1 3 1 0 3 1 1 【輸出樣例1】 11 【輸入樣例2】 7 9 4 2 3 0 7 2 0 6 3 1 6 1 0 2 1 1 3 3 1 5 2 0 2 2 1 7 1 0 【輸出樣例2】 21 【數據範圍】 對於20%的數據,N,K<=20,M<=100 對於40%的數據,N,K<=100,M<=1000 對於60%的數據,N,K<=1000,M<=100000 對於100%的數據,N,K<=50000,M<=100000 資源約定: 峰值內存消耗(含虛擬機) < 256M CPU消耗 < 5000ms 請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。 所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。 註意:不要使用package語句。不要使用jdk1.7及以上版本的特性。 註意:主類的名字必須是:Main,否則按無效代碼處理。
PS:以下代碼為暴力求解,僅作參考>~<
1 import java.util.Scanner; 2 3 public class Main { 4 public static int n, m , k; 5 public static int[][] value; 6 7 public void getResult() { 8 int max = Integer.MIN_VALUE; 9 for(int i = 1;i < n;i++) { 10 if(value[i][i+1] == 0) { 11 value[i][i+1] = 1; 12 int temp = 0; 13 for(int k = 1;k <= n;k++) { 14 temp++; 15 int t = k - 1; 16 while(t >= 1) { //尋找左邊連通水磊 17 if(value[t][t+1] == 1) { 18 temp++; 19 t--; 20 } else 21 break; 22 } 23 t = k + 1; 24 while(t <= n) { //尋找右邊連通水磊 25 if(value[t][t-1] == 1) { 26 temp++; 27 t++; 28 } else 29 break; 30 } 31 } 32 max = Math.max(max, temp); 33 value[i][i+1] = 0; 34 } 35 } 36 System.out.println(max); 37 } 38 39 public static void main(String[] args) { 40 Main test = new Main(); 41 Scanner in = new Scanner(System.in); 42 n = in.nextInt(); 43 m = in.nextInt(); 44 k = in.nextInt(); 45 value = new int[n + 1][n + 1]; 46 for(int i = 0;i < m;i++) { 47 int x = in.nextInt(); 48 @SuppressWarnings("unused") 49 double y = in.nextDouble(); 50 int c = in.nextInt(); 51 if(c == 0) 52 value[x][x - 1] = 1; //單向向左連通 53 else 54 value[x][x + 1] = 1; //單向向右連通 55 } 56 test.getResult(); 57 } 58 }
算法筆記_206:第五屆藍橋杯軟件類決賽真題(Java語言A組)