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

算法筆記_204:第四屆藍橋杯軟件類決賽真題(Java語言C組)

系統 主類 文字 新節點 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組)