1. 程式人生 > >算法筆記_206:第五屆藍橋杯軟件類決賽真題(Java語言A組)

算法筆記_206:第五屆藍橋杯軟件類決賽真題(Java語言A組)

理論 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 列為 11 <= 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組)