2013年第四屆藍橋杯省賽試題及詳解(Java本科C組)
藍橋杯歷年真題題目及題解目錄彙總
- 結果填空 (滿分3分)
- 結果填空 (滿分5分)
- 結果填空 (滿分8分)
- 結果填空 (滿分12分)
- 程式碼填空 (滿分6分)
- 程式碼填空 (滿分11分)
- 程式設計(滿分4分)
- 程式設計(滿分12分)
- 程式設計(滿分15分)
- 程式設計(滿分24分)
1.標題: 猜年齡
美國數學家維納(N.Wiener)智力早熟,11歲就上了大學。他曾在1935~1936年應邀來中國清華大學講學。
一次,他參加某個重要會議,年輕的臉孔引人注目。於是有人詢問他的年齡,他回答說:
“我年齡的立方是個4位數。我年齡的4次方是個6位數。這10個數字正好包含了從0到9這10個數字,每個都恰好出現1次。”
請你推算一下,他當時到底有多年輕。
通過瀏覽器,直接提交他那時的年齡數字。
注意:不要提交解答過程,或其它的說明文字。
18,這題完全不用把0-9這個限制條件敲到程式碼上,光是4位6位就篩剩幾個數了,列印出來觀察更快
public class _01_猜年齡1 {
public static void main(String[] args) {
for(int i=11;i<=150;i++) {
int a = i*i*i;
int b = i*i*i*i;
if(a>=1000 && a<=9999 && b>=100000 && b<=999999)
System.out.println(i+" "+a+" "+b);
}
}
}
2.標題: 組素數
素數就是不能再進行等分的數。比如:2 3 5 7 11 等。
9 = 3 * 3 說明它可以3等分,因而不是素數。
我們國家在1949年建國。如果只給你 1 9 4 9 這4個數字卡片,可以隨意擺放它們的先後順序(但卡片不能倒著擺放啊,我們不是在腦筋急轉彎!),那麼,你能組成多少個4位的素數呢?
比如:1949,4919 都符合要求。
請你提交:能組成的4位素數的個數,不要羅列這些素數!!
注意:不要提交解答過程,或其它的輔助說明文字。
我覺得可以先人工列舉全排,4!/2!=12個吧,比你寫個全排函式快一些,而且普通的全排函式面對重複數字不能篩重,得出的是4!,所以人工完了之後就求素數個數吧答案:6 (1499,1949,4919,9419,9491,9941)
public class _02_組素數1 {
public static void main(String[] args) {
int[] a = new int[] {1499,1949,1994,9149,9194,9914,4199,4919,4991,9419,9491,9941};
int ans=0;
for(int i=0;i<a.length;i++) {
boolean flag = true;
for(int j=2;j*j<=a[i];j++)
if(a[i]%j==0) {
flag = false;
break;
}
if(flag) {
ans++;
System.out.println(a[i]);
}
}
System.out.println(ans);
}
}
也貼一下通過全排列的做法吧,多個步雜湊查重
import java.util.HashSet;
import java.util.Set;
//素數判定、素數生成(篩法)、質因數分解
//有重複元素的全排列+檢查
public class _02組素數 {
/**
* 處理從k開始的排列
* @param arr
* @param k
*/
static void f(int[] arr, int k) {
if (k == 4)//前面都已確定
check(arr);
for (int i = k; i < 4; i++) {
//交換
int t = arr[k];
arr[k] = arr[i];
arr[i] = t;
f(arr, k + 1);
t = arr[k];
arr[k] = arr[i];
arr[i] = t;
}
}
static Set<Integer> set = new HashSet<Integer>();
private static void check(int[] arr) {
int x = arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
boolean flag = true;
for (int i = 2; i <= Math.sqrt(x); i++) {
if (x % i == 0) {
flag = false;
System.out.println(x+" false");
break;
}
}
if (flag) {
set.add(x);
System.out.println(x+" true");
}
}
public static void main(String[] args) {
int[] arr = {1, 4, 9, 9};
f(arr, 0);
System.out.println(set.size());
}
}
3.標題: 馬虎的算式
小明是個急性子,上小學的時候經常把老師寫在黑板上的題目抄錯了。
有一次,老師出的題目是:36 x 495 = ?
他卻給抄成了:396 x 45 = ?
但結果卻很戲劇性,他的答案竟然是對的!!
因為 36 * 495 = 396 * 45 = 17820
類似這樣的巧合情況可能還有很多,比如:27 * 594 = 297 * 54
假設 a b c d e 代表1~9不同的5個數字(注意是各不相同的數字,且不含0)
能滿足形如: ab * cde = adb * ce 這樣的算式一共有多少種呢?
請你利用計算機的優勢尋找所有的可能,並回答不同算式的種類數。
滿足乘法交換律的算式計為不同的種類,所以答案肯定是個偶數。
答案直接通過瀏覽器提交。
注意:只提交一個表示最終統計種類數的數字,不要提交解答過程或其它多餘的內容。
142,暴力到沒朋友,填空題暴力列舉就好
import java.util.Scanner;
public class _02_馬虎的算式1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int ans=0;
for(int a=1;a<=9;a++)
for(int b=1;b<=9;b++) {
if(b==a)
continue;
for(int c=1;c<=9;c++) {
if(c==a || c==b)
continue;
for(int d=1;d<=9;d++) {
if(d==a || d==b || d==c)
continue;
for(int e=1;e<=9;e++) {
if(e==a || e==b || e==c || e==d)
continue;
if((10*a+b)*(100*c+10*d+e)==(100*a+10*d+b)*(10*c+e))//ab * cde = adb * ce
ans++;
}
}
}
}
System.out.println(ans);
}
}
4.標題: 第39級臺階
小明剛剛看完電影《第39級臺階》,離開電影院的時候,他數了數禮堂前的臺階數,恰好是39級!
站在臺階前,他突然又想著一個問題:
如果我每一步只能邁上1個或2個臺階。先邁左腳,然後左右交替,最後一步是邁右腳,也就是說一共要走偶數步。那麼,上完39級臺階,有多少種不同的上法呢?
請你利用計算機的優勢,幫助小明尋找答案。
要求提交的是一個整數。
注意:不要提交解答過程,或其它的輔助說明文字。
答案:51167078,一定要走偶數步?那不如一次就遞迴2步把,2步合成一步
public class _04第39級臺階1 {
public static void main(String[] args) {
System.out.println(f(39));
}
static int f(int x) {
if(x==0)
return 1;
if(x<0)
return 0;
return f(x-2)+2*f(x-3)+f(x-4);//左腳1步右腳2步和右腳1步左腳2步不一樣的哦
}
}
5.標題:有理數類
有理數就是可以表示為兩個整數的比值的數字。一般情況下,我們用近似的小數表示。但有些時候,不允許出現誤差,必須用兩個整數來表示一個有理數。
這時,我們可以建立一個“有理數類”,下面的程式碼初步實現了這個目標。為了簡明,它只提供了加法和乘法運算。
class Rational
{
private long ra;
private long rb;
private long gcd(long a, long b){
if(b==0) return a;
return gcd(b,a%b);
}
public Rational(long a, long b){
ra = a;
rb = b;
long k = gcd(ra,rb);
if(k>1){ //需要約分
ra /= k;
rb /= k;
}
}
// 加法
public Rational add(Rational x){
return ________________________________________; //填空位置
}
// 乘法
public Rational mul(Rational x){
return new Rational(ra*x.ra, rb*x.rb);
}
public String toString(){
if(rb==1) return "" + ra;
return ra + "/" + rb;
}
}
使用該類的示例:
Rational a = new Rational(1,3);
Rational b = new Rational(1,6);
Rational c = a.add(b);
System.out.println(a + "+" + b + "=" + c);
請分析程式碼邏輯,並推測劃線處的程式碼,通過網頁提交
注意:僅把缺少的程式碼作為答案,千萬不要填寫多餘的程式碼、符號或說明文字!!
數學通分:a/b + c/d = (a*d+b*c)/(b*d)
- new Rational(ra*x.rb+rb*x.ra, rb*x.rb)
- new Rational(this.ra * x.rb + x.ra * this.rb, this.rb * x.rb)
上面的答案都行,不要this是觀察到乘法函式也沒寫
6.標題:逆波蘭表示式
正常的表示式稱為中綴表示式,運算子在中間,主要是給人閱讀的,機器求解並不方便。
例如:3 + 5 * (2 + 6) - 1
而且,常常需要用括號來改變運算次序。
相反,如果使用逆波蘭表示式(字首表示式)表示,上面的算式則表示為:
- + 3 * 5 + 2 6 1
不再需要括號,機器可以用遞迴的方法很方便地求解。
為了簡便,我們假設:
1. 只有 + - * 三種運算子
2. 每個運算數都是一個小於10的非負整數
下面的程式對一個逆波蘭表示串進行求值。
其返回值為一個陣列:其中第一元素表示求值結果,第二個元素表示它已解析的字元數。
static int[] evaluate(String x)
{
if(x.length()==0) return new int[] {0,0};
char c = x.charAt(0);
if(c>='0' && c<='9') return new int[] {c-'0',1};
int[] v1 = evaluate(x.substring(1));
int[] v2 = __________________________________________; //填空位置
int v = Integer.MAX_VALUE;
if(c=='+') v = v1[0] + v2[0];
if(c=='*') v = v1[0] * v2[0];
if(c=='-') v = v1[0] - v2[0];
return new int[] {v,1+v1[1]+v2[1]};
}
請分析程式碼邏輯,並推測劃線處的程式碼,通過網頁提交。
注意:僅把缺少的程式碼作為答案,千萬不要填寫多餘的程式碼、符號或說明文字!!
evaluate(x.substring(1+v1[1])),不會就試到會?樣例自己弄簡單的套
結構應該是這樣的:
(操作符佔的長度,如果從大的整體看一次長度只能為1)(v1佔的長度)(剩下不就是v2佔的長度,為v1+1剩下部分)
7.標題:核桃的數量
小張是軟體專案經理,他帶領3個開發組。工期緊,今天都在加班呢。為鼓舞士氣,小張打算給每個組發一袋核桃(據傳言能補腦)。他的要求是:
1. 各組的核桃數量必須相同
2. 各組內必須能平分核桃(當然是不能打碎的)
3. 儘量提供滿足1,2條件的最小數量(節約鬧革命嘛)
程式從標準輸入讀入:
a b c
a,b,c都是正整數,表示每個組正在加班的人數,用空格分開(a,b,c<30)
程式輸出:
一個正整數,表示每袋核桃的數量。
例如:
使用者輸入:
2 4 5
程式輸出:
20
再例如:
使用者輸入:
3 1 1
程式輸出:
3
資源約定:
峰值記憶體消耗(含虛擬機器) < 64M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。
注意:主類的名字必須是:Main,否則按無效程式碼處理。
題目的意思是求3個數的最小公倍數,瞭解下簡單數論,擴充套件歐幾里得,同餘定理,
對於gcd,lcm 都可以通過先寫2個數的,在套用2個數的求n個數的,和數學的思想一致,先求出2個數的最小公倍數再求3個數的
import java.util.Scanner;
public class _07核桃的數量1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println(lcm(in.nextInt(),in.nextInt(),in.nextInt()));
}
static int gcd(int a,int b) {
if(b==0)
return a;
return gcd(b,a%b);
}
static int gcd(int a,int b,int c) {
return gcd(gcd(a,b),c);
}
static int lcm(int a,int b) {
return a*b/gcd(a,b);
}
static int lcm(int a,int b,int c) {
int s = lcm(a,b);
return s*c/gcd(s,c);
}
}
8.標題:列印十字圖
小明為某機構設計了一個十字型的徽標(並非紅十字會啊),如下所示(可參見p1.jpg)
$$$$$$$$$$$$$
$ $
$$$ $$$$$$$$$ $$$
$ $ $ $
$ $$$ $$$$$ $$$ $
$ $ $ $ $ $
$ $ $$$ $ $$$ $ $
$ $ $ $ $ $ $
$ $ $ $$$$$ $ $ $
$ $ $ $ $ $ $
$ $ $$$ $ $$$ $ $
$ $ $ $ $ $
$ $$$ $$$$$ $$$ $
$ $ $ $
$$$ $$$$$$$$$ $$$
$ $
$$$$$$$$$$$$$
對方同時也需要在電腦dos視窗中以字元的形式輸出該標誌,並能任意控制層數。
為了能準確比對空白的數量,程式要求對行中的空白以句點(.)代替。
輸入格式:
一個正整數 n (n<30) 表示要求列印圖形的層數
輸出:
對應包圍層數的該標誌。
例如:
使用者輸入:
1
程式應該輸出:
..$$$$$..
..$...$..
$$$.$.$$$
$...$...$
$.$$$$$.$
$...$...$
$$$.$.$$$
..$...$..
..$$$$$..
再例如:
使用者輸入:
3
程式應該輸出:
..$$$$$$$$$$$$$..
..$...........$..
$$$.$$$$$$$$$.$$$
$...$.......$...$
$.$$$.$$$$$.$$$.$
$.$...$...$...$.$
$.$.$$$.$.$$$.$.$
$.$.$...$...$.$.$
$.$.$.$$$$$.$.$.$
$.$.$...$...$.$.$
$.$.$$$.$.$$$.$.$
$.$...$...$...$.$
$.$$$.$$$$$.$$$.$
$...$.......$...$
$$$.$$$$$$$$$.$$$
..$...........$..
..$$$$$$$$$$$$$..
請仔細觀察樣例,尤其要注意句點的數量和輸出位置。
資源約定:
峰值記憶體消耗(含虛擬機器) < 64M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。
注意:主類的名字必須是:Main,否則按無效程式碼處理。
說實話,看見這種列印的題目就不想做了
import java.util.Scanner;
//2013-C-C第八題一樣的
public class _08列印十字圖 {
static int N, L = 0, R;
static char[][] arr;
static void deal(int n) {
//n=3,總寬17,最大下標16
int l,r;
l= (N-n)*2;//最小下標
r=l+9+4*(n-1)-1;//最大下標
for (int i = l+2; i <= r-2; i++) {
arr[l][i] = '$';
arr[r][i] = '$';
}
arr[l+1][l+2] = '$';
arr[l+1][r-2] = '$';
arr[r-1][l+2] = '$';
arr[r-1][r-2] = '$';
for (int i = l; i < l+3; i++) {
arr[l+2][i] = '$';
arr[r - 2][i] = '$';
}
for (int i = r; i >r-3 ; i--) {
arr[l+2][i] = '$';
arr[r - 2][i] = '$';
}
for (int i = l+3; i <= r-3; i++) {
arr[i][l] = '$';
arr[i][r] = '$';
}
}
static void printAll() {
for (int i = 0; i <= R; i++) {
for (int j = 0; j <= R; j++) {
if (arr[i][j] != '$') arr[i][j] = '.';
System.out.print(arr[i][j]);
}
System.out.println();
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
R = 9 + 4 * (N - 1) - 1;//最大下標
arr = new char[R+1][R+1];
for (int i = N; i >=1 ; i--) {
deal(i);
}
int c_i=2*N+2;
int c_j=2*N+2;
arr[c_i][c_j]='$';
for (int i = c_i-2; i < c_i+3; i++) {
arr[c_i][i]='$';
}
for (int i = c_i-2; i < c_i+3; i++) {
arr[i][c_j]='$';
}
printAll();
}
}
9.標題:買不到的數目
小明開了一家糖果店。他別出心裁:把水果糖包成4顆一包和7顆一包的兩種。糖果不能拆包賣。
小朋友來買糖的時候,他就用這兩種包裝來組合。當然有些糖果數目是無法組合出來的,比如要買 10 顆糖。
你可以用計算機測試一下,在這種包裝情況下,最大不能買到的數量是17。大於17的任何數字都可以用4和7組合出來。
本題的要求就是在已知兩個包裝的數量時,求最大不能組合出的數字。
輸入:
兩個正整數,表示每種包裝中糖的顆數(都不多於1000)
要求輸出:
一個正整數,表示最大不能買到的糖數
不需要考慮無解的情況
例如:
使用者輸入:
4 7
程式應該輸出:
17
再例如:
使用者輸入:
3 5
程式應該輸出:
7
資源約定:
峰值記憶體消耗(含虛擬機器) < 64M
CPU消耗 < 3000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。
注意:主類的名字必須是:Main,否則按無效程式碼處理。
這題有個數學公式秒殺 a*b-(a+b),正常人想不到可以通過暴力列舉撈點分,甚至AC
public class _09買不到的數目 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
// System.out.println(a*b-a-b);
int max = a * b;
Set<Integer> ss = new HashSet<Integer>();
//從0開始列舉到max
for (int x = 0; a * x < max; x++) {
for (int y = 0; a * x + b * y < max; y++) {
ss.add(a * x + b * y);//用不小於0的x和y與係數能組合出來的數加入set中
}
}
for (int i = max - 1; i >= 0; i--) {
if (!ss.contains(i)) { //查詢第一個不在set中的值
System.out.println(i);
break;
}
}
}
}
10.標題:剪格子
如圖p1.jpg所示,3 x 3 的格子中填寫了一些整數。
我們沿著圖中的紅色線剪開,得到兩個部分,每個部分的數字和都是60。
本題的要求就是請你程式設計判定:對給定的m x n 的格子中的整數,是否可以分割為兩個部分,使得這兩個區域的數字和相等。
如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。
如果無法分割,則輸出 0
程式輸入輸出格式要求:
程式先讀入兩個整數 m n 用空格分割 (m,n<10)
表示表格的寬度和高度
接下來是n行,每行m個正整數,用空格分開。每個整數不大於10000
程式輸出:在所有解中,包含左上角的分割區可能包含的最小的格子數目。
例如:
使用者輸入:
3 3
10 1 52
20 30 1
1 2 3
則程式輸出:
3
再例如:
使用者輸入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100
則程式輸出:
10
(參見p2.jpg)
資源約定:
峰值記憶體消耗(含虛擬機器) < 64M
CPU消耗 < 5000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。
注意:主類的名字必須是:Main,否則按無效程式碼處理。
左邊圖1,右邊圖2
思路和普通的dfs搜尋+回溯一樣,只是這裡有個坑,可能會剪成3塊,搜出答案的時候,先把和第一個連線的答案存起來,然後用一次dfs求聯通塊判斷,最後別忘了 把求聯通塊時標記的vis復原,所以考慮到這個就不用boolean陣列標記了,改成int,靈活
import java.util.Scanner;
public class _09剪格子 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
m = in.nextInt();
n = in.nextInt();
a = new int[n][m];
vis = new int[n][m];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) {
a[i][j] = in.nextInt();
sum += a[i][j];
}
if(sum%2==1) {
System.out.println(0);
return;
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) {
vis[i][j] = 1;
dfs(i,j,a[i][j],1);
init();
}
if(ans==999999)
System.out.println(0);
else
System.out.println(ans);
}
static int n,m,sum=0,ans=999999,q=0;
static int[][] a;
static int[][] vis;
static int[] dx = new int[] {0,1,0,-1};
static int[] dy = new int[] {1,0,-1,0};
static void dfs(int x,int y,int now,int t) {
if(now==sum/2) {
int tmp;
if(vis[0][0]==1)
tmp = t;
else
tmp = m*n-t;
// for(int i=0;i<n;i++) {
// for(int j=0;j<m;j++)
// System.out.print(vis[i][j]+" ");
// System.out.println();
// }
// System.out.println();
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)//判斷有沒剪成3部分了= =
if(vis[i][j]!=1) {
q=0;
dfs_check(i, j);
for(int ii=0;ii<n;ii++)
for(int jj=0;jj<m;jj++)
if(vis[ii][jj]==-1)
vis[ii][jj] = 0;
if(q!=m*n-t)
return;
break;//判斷一次就行了
}
ans = Math.min(ans, tmp);
return;
}
if(now>sum/2 || t>ans)//稍微剪剪枝
return;
for(int i=0;i<4;i++) {
int j = x + dx[i];
int k = y + dy[i];
if(ok(j,k)) {
vis[j][k] = 1;
dfs(j,k,now+a[j][k],t+1);
vis[j][k] = 0;
}
}
}
static void init() {
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
vis[i][j] = 0;
}
static boolean ok(int x,int y) {
return x>=0 && x<n && y>=0 && y<m && vis[x][y]!=1;
}
static void dfs_check(int x,int y) {
q++;
vis[x][y] = -1;
for(int i=0;i<4;i++) {
int j = x + dx[i];
int k = y + dy[i];
if(j>=0 && j<n && k>=0 && k<m && vis[j][k]==0)
dfs_check(j,k);
}
}
}
貼一貼官方的c++程式碼
//
// Created by zhengwei .
// Copyright © 2019 lanqiao. All rights reserved.
//
/*
標題:剪格子
如圖p1.jpg所示,3 x 3 的格子中填寫了一些整數。
我們沿著圖中的紅色線剪開,得到兩個部分,每個部分的數字和都是60。
本題的要求就是請你程式設計判定:對給定的m x n 的格子中的整數,是否可以分割為兩個部分,使得這兩個區域的數字和相等。
如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。
如果無法分割,則輸出 0
程式輸入輸出格式要求:
程式先讀入兩個整數 m n 用空格分割 (m,n<10)
表示表格的寬度和高度
接下來是n行,每行m個正整數,用空格分開。每個整數不大於10000
程式輸出:在所有解中,包含左上角的分割區可能包含的最小的格子數目。
例如:
使用者輸入:
3 3
10 1 52
20 30 1
1 2 3
則程式輸出:
3
再例如:
使用者輸入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100
則程式輸出:
10
(參見p2.jpg)
資源約定:
峰值記憶體消耗 < 64M
CPU消耗 < 5000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
*/
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#define mk(i,j) make_pair(i,j)
using namespace std;
int m, n;
int total;
int g[10][10];
int ans;
/*抽象了一種剪輯方法*/
class Cut {
public:
set<pair<int, int> > grids;//包含若干格子
int sum;//所有格子的數值的求和
};
/**
* 將st中的元素拷貝到新set中
* @param st
* @return
*/
set<pair<int, int> > copySet(set<pair<int, int> > &st) {
set<pair<int, int> >::iterator iter = st.begin();
set<pair<int, int> > ans;
while (iter != st.end()) {
// 重新mkpair,加入新set中
ans.insert(*iter);
iter++;
}
return ans;
}
void add(int sum, int i, int j, set<pair<int, int> > &grids, Cut *&cut_new) {
const pair<int, int> &pair_n = make_pair(i , j);
// 深度拷貝set
set<pair<int, int> > grids_copy=copySet(grids);
grids_copy.insert(pair_n);
cut_new->grids=grids_copy;
cut_new->sum=sum+g[i][j];
}
vector<Cut *> vs[100];//分別儲存格子數為1~100的各種剪法
int main(int argc, const char *argv[]) {
scanf("%d %d", &m, &n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
scanf("%d", &g[i][j]);
total += g[i][j];
}
}
// 第一個格子就是一半
if (g[0][0] == total / 2) {
printf("%d\n", 1);
return 0;
}
/*左上角格子,只有一種剪法,加入v[1]*/
Cut *c = new Cut();
const pair<int, int> p = make_pair(0, 0);
c->grids.insert(p);
c->sum = g[0][0];
vs[1].push_back(c);//只包含一個格子且包含00的只有一種剪法
for (int i = 2; i <= m * n; ++i) {
// i是格子數,用vs[i-1]裡面的來生成
//迭代vs[i-1]裡面的所有剪法
for (int j = 0; j < vs[i - 1].size(); ++j) {
// pCut代表一種剪輯方法
Cut *pCut = vs[i - 1][j];
// 這種剪輯方法裡面記錄了所有格子,這些格子每個都擴充套件一個,即形成個數+1的剪法
set<pair<int, int> > &grids = pCut->grids;
int sum = pCut->sum;
set<pair<int, int> >::iterator iter = grids.begin();
// 迭代所有的格子,嘗試新增它的鄰居
while (iter != grids.end()) {
const pair<int, int> &p = *iter;//代表一個格子的座標
int x=p.first;
int y=p.second;
if(x+1<n&&grids.find(mk(x+1,y))==grids.end()){//下方,能走通且下方格子不在當前集合中
Cut *cut_new=new Cut();//生成一個新的剪法
add(sum, x+1, y, grids, cut_new);//將原有的格子全部拷入,再增加當前試探的新的格子
if(cut_new->sum==total/2){
printf("%d\n", i);
return 0;
}else if(cut_new->sum<total/2)
vs[i].push_back(cut_new);
}
if(x-1>=0&&grids.find(mk(x-1,y))==grids.end()){//上方
Cut *cut_new=new Cut();
add(sum, x-1, y, grids, cut_new);
if(cut_new->sum==total/2){
printf("%d\n", i);
return 0;
}else if(cut_new->sum<total/2)
vs[i].push_back(cut_new);
}
if(y+1<m&&grids.find(mk(x,y+1))==grids.end()){//右方
Cut *cut_new=new Cut();
add(sum, x, y+1, grids, cut_new);
if(cut_new->sum==total/2){
printf("%d\n", i);
return 0;
} else if(cut_new->sum<total/2)
vs[i].push_back(cut_new);
}
if(y-1>=0&&grids.find(mk(x,y-1))==grids.end()){//左方
Cut *cut_new=new Cut();
add(sum, x, y-1, grids, cut_new);
if(cut_new->sum==total/2){
printf("%d\n", i);
return 0;
}else if(cut_new->sum<total/2)
vs[i].push_back(cut_new);
}
iter++;
}
}
}
printf("%d\n", 0);
return 0;
}
小結
01 猜年齡 簡單列舉 02 組素數 帶重複元素的全排列+素數判定,用到set去重 03 馬虎的算式 列舉5個變數,組合後,進行檢查 *04 第39級臺階 走樓梯的一個變形,記錄走的步數,本質是遞迴思維 05 有理數類 物件導向和分數加法(通分和約分) *06 逆波蘭表示式 遞迴的整體思維 07 核桃的數量 簡單列舉 08 列印十字圖 先寫死,再變活 **09 買不到的數目 數學 **10 剪格子 深搜+回溯+剪枝 搜尋(列舉=迭代和遞迴,dfs(含回溯和剪枝)、bfs、二分查詢) 模擬
相關文章
- 2014年第五屆藍橋杯省賽試題及詳解(Java本科C組)Java
- 2018年第九屆藍橋杯省賽試題及詳解(Java本科A組)Java
- 2018年第九屆藍橋杯省賽試題及詳解(Java本科B組)Java
- 2013第四屆藍橋杯省賽C++A組【第一題:高斯日記】C++
- 藍橋杯歷年(省賽)試題彙總及試題詳解
- 2013第四屆藍橋杯省賽C++B組【第六題:三部排序】C++排序
- 藍橋杯__省賽__第七屆__C/C++__大學A組C++
- 藍橋杯__省賽__第八屆__C/C++__大學A組C++
- 藍橋杯__省賽__第九屆__C/C++__大學A組C++
- 第四屆藍橋杯C/C++本科B組第二道大題C++
- 第十五屆藍橋杯軟體賽省賽C/C++B 組題解C++
- 第十三屆藍橋杯省賽A組
- 【藍橋杯考前突擊】第十屆藍橋杯省賽C/C++大學B組 試題 D 數的分解C++
- 第十三屆藍橋杯省賽C/C++ B組C++
- 試題B:小球反彈(第十五屆藍橋杯省賽B組c/c++組)C++
- 第九屆藍橋杯軟體類省賽 Java B組 題目及解析Java
- 2018第九屆藍橋杯省賽C++B組【第四題:測試次數】C++
- 2016年藍橋杯C/C++組省賽第四題--快速排序C++排序
- 第九屆藍橋杯省賽C++A組 倍數問題(dfs)C++
- 第十四屆藍橋杯省賽C++ B組(個人經歷 + 題解)C++
- 2019年省賽第十屆藍橋杯B組C/C++試題H解 等差數列C++
- 第六屆藍橋杯省賽CC++B組C++
- 第十屆藍橋杯省賽C++B組 等差數列C++
- 第十五屆藍橋杯C++B組省賽總結C++
- 第十五屆藍橋杯大賽軟體賽省賽 C/C++ 大學 A 組C++
- 2015年藍橋杯六屆省賽大學B組真題
- 2017第八屆藍橋杯C/C++ B組省賽第二題 秒解C++
- 歷屆藍橋杯省賽(C、C++)的答案(轉)C++
- 2016年省賽第七屆藍橋杯B組C/C++第九題解 交換瓶子C++
- 2013藍橋杯題解c++A組C++
- 2013藍橋杯題解c組C++C++
- 2012年第三屆藍橋杯C/C++程式設計本科B組省賽 奇怪的比賽(結果填空)C++程式設計
- 第七屆藍橋杯大賽個人賽省賽(軟體類)真題 C語言A組 1C語言
- 2012年第三屆藍橋杯C/C++程式設計本科B組省賽 放棋子(程式碼填空)C++程式設計
- 第十屆藍橋杯C++國賽B組部分題解(假題解)C++
- 2012年 藍橋杯預賽 java 本科 題目Java
- 藍橋杯2014年第五屆決賽C_C++程式設計本科B組C++程式設計
- 2012年第三屆藍橋杯C/C++程式設計本科B組省賽 大數乘法(程式碼填空)C++程式設計