藍橋杯備戰——暴力枚舉篇

一、年齡問題

問題描述

美國數學家維納(N.Wiener)智力早熟,11 歲就上了大學。他曾在 1935~1936 年應
邀來中國清華大學講學。一次,他參加某個重要會議,年輕的臉孔引人注目。於是
有人詢問他的年齡,他回答說:“我年齡的立方是個 4 位數。我年齡的 4 次方是個
6 位數。這 10 個數字正好包含了從 0 到 9 這 10 個數字,每個都恰好出現 1 次。”
請你推算一下,他當時到底有多年輕。

解題思路

找好界限 “我年齡的立方是個 4 位數。我年齡的 4 次方是個
6 位數” 所以在 18和25 之間 當然 這道題碰巧答案就是 18
所以這道題着重看下在判斷一串數字 這 10 個數字正好包含了從 0 到 9 這 10 個數字,每個都恰好出現 1 次 是個技巧

public class Demo01_年齡問題 {

	public static void main(String[] args) {
	
		
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		//如下代碼
		String sum;
		for(int i = 10; i<25; i++) {
			sum = i*i*i +""+i*i*i*i;

			int k = 0; 
			while(sum.lastIndexOf(sum.charAt(k)) == k) {
			    if(k==9) {
			    	System.out.println(i);
			    	return;
			    }
			    k++;
			}	
		}

	}

}

二、統計方形

問題描述

有一個n*m方格的棋盤,求其方格包含多少正方形、長方形
輸入格式
n,m規定m小於等於5000,n小於等於5000
輸出格式
方格包含多少正方形、長方形
輸入輸出樣例
輸入
2 3
輸出
8 10

解題思路

1.數據規模小於100時 用模擬法即可 也是枚舉的一個思想

import java.util.Scanner;

/**
 * 
 * @author sjf666
 * 
 * 2020年4月13日下午9:53:58
 */

//暴力 遍歷每個棋盤結點 在那之上 再進行不同邊長正方形、長方形的統計
public class Demo05_統計方形 {

	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int n =sc.nextInt();
		int m =sc.nextInt();
		int[][] map = new int[n][m];
		
		long  zsum = 0, csum= 0;
		long  sum = 0;
		for(int i = 0; i< map.length; i++) {
			for(int j = 0; j<map[i].length; j++) {
			
				//正方形的統計
				int d = 1;
				while(i+d <= n && j+d <= m) {
					zsum++;
					d++;
				}
				
				//長方形的統計
				int c = 1;
				while(i+c <= n ) {
					int k = 1;
					while(j+k <= m) {
						if(k != c)
						csum++;
						k++;
					}
					c++;
				}
				
			}
		}

		System.out.print(zsum+" "+csum);
	}

}

2.數據規模大點 這是O(n^3) 當然會超時

所以 數學方法 降到 O(n^2)


import java.util.Scanner;

/**
 * 
 * @author sjf666
 * 
 * 2020年4月13日下午9:53:58
 */
public class Demo05_統計方形 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int n =sc.nextInt();
		int m =sc.nextInt();
		int[][] map = new int[n][m];
		
		long  zsum = 0, csum= 0;
		long  sum = 0;
		for(int i = 0; i< map.length; i++) {
			for(int j = 0; j<map[i].length; j++) {
				
				//數學果然。。
				//sum 是所有矩形 
				//zsum是正方形的個數 ,csum = sum - zsum
				sum+=(i+1)*(j+1);
				zsum += Math.min(i+1, j+1);	
			}
		}

		csum = sum - zsum;
		System.out.print(zsum+" "+csum);
	}

}

三、火星人

問題描述

人類終於登上了火星的土地並且見到了神祕的火星人。人類和火星人都無法理解對方的語言,但是我們的科學家發明了一種用數字交流的方法。這種交流方法是這樣的,首先,火星人把一個非常大的數字告訴人類科學家,科學家破解這個數字的含義後,再把一個很小的數字加到這個大數上面,把結果告訴火星人,作爲人類的回答。

火星人用一種非常簡單的方式來表示數字――掰手指。火星人只有一隻手,但這隻手上有成千上萬的手指,這些手指排成一列,分別編號爲1,2,3…。火星人的任意兩根手指都能隨意交換位置,他們就是通過這方法計數的。

一個火星人用一個人類的手演示瞭如何用手指計數。如果把五根手指――拇指、食指、中指、無名指和小指分別編號爲1,2,3,4和5,當它們按正常順序排列時,形成了5位數12345,當你交換無名指和小指的位置時,會形成5位數12354,當你把五個手指的順序完全顛倒時,會形成54321,在所有能夠形成的120個5位數中,12345最小,它表示1;12354第二小,它表示2;54321最大,它表示120。下表展示了只有3根手指時能夠形成的6個3位數和它們代表的數字:

三進制數

123
132
213
231
312
321

代表的數字

1
2
3
4
5
6

現在你有幸成爲了第一個和火星人交流的地球人。一個火星人會讓你看他的手指,科學家會告訴你要加上去的很小的數。你的任務是,把火星人用手指表示的數與科學家告訴你的數相加,並根據相加的結果改變火星人手指的排列順序。輸入數據保證這個結果不會超出火星人手指能表示的範圍。
輸入格式

共三行。
第一行一個正整數N,表示火星人手指的數目(1≤N≤10000)。
第二行是一個正整數M,表示要加上去的小整數(1≤M≤100)。
下一行是1到N這N個整數的一個排列,用空格隔開,表示火星人手指的排列順序。
輸出格式

N個整數,表示改變後的火星人手指的排列順序。每兩個相鄰的數中間用一個空格分開,不能有多餘的空格。

解決思路

小白一個
此解法拿不到滿分 但是應對藍橋杯的題用此方法應該是可以的了

此題 是一個經典全排列的變形

首先我們要確定給出的火星人手指排列 在全排列的第幾層
然後 相加上那個小數
然後再找到 對應的層數的全排列 輸出即可


import java.util.Scanner;

/**
 * 
 * @author sjf666
 * 
 * 2020年4月14日下午3:02:03
 */
/*
 *此題  是一個經典全排列的變形
 *
 *首先我們要確定給出的火星人手指 在全排列的第幾層 也就是找到這個手指
 *然後 相加
 *然後再找到 相加到的手指
 *easy
 */
public class Demo07_火星人 {

	static int N;  //火星人的手指個數
	static int M;  //加上去的一個小數字
	static int[] ans = new int[10000];  //存儲全排列的數組
	static int[] book = new int[100001];  //標記數組
	static int[] num1 = new int[10000];  //火星人原始的手指個數
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
	    M = sc.nextInt();
		
		for(int i = 0; i < N; i++)
			num1[i] = sc.nextInt();
		
		dfs(0);

	}

	static int cnt = 1;  //記錄每個全排列所表達的十進制數字
	public static void dfs(int step) {
		
		if(step == N) {
			check();
			cnt++;
			return;
		}
			
		for(int i = 1; i <= N; i++) {
			if(book[i] == 0) {
				ans[step] = i;
				book[i] = 1;
				dfs(step+1);
				book[i] = 0;
			}
		}
		
	}
	
	static int num2;  //
	public static void check() {
		
		int i;
		if(num2 == 0) {
		for( i = 0; i < N; i++) 
			if(num1[i] != ans[i]) 
				break;
        	if(i == N )
        		num2 = cnt+M;
		}
        else if(num2 == cnt)
        for(int j = 0; j < N; j++)
        	if(j == N-1)
        		System.out.println(ans[j]);
        	else 
        		System.out.print(ans[j]+" ");
	}
	
	
}

四、帶分數

問題描述

100 可以表示爲帶分數的形式:100 = 3 + 69258 / 714

還可以表示爲:100 = 82 + 3546 / 197

注意特徵:帶分數中,數字1~9分別出現且只出現一次(不包含0)。

類似這樣的帶分數,100 有 11 種表示法。

題目要求:
從標準輸入讀入一個正整數N (N<1000*1000)
程序輸出該數字用數碼1~9不重複不遺漏地組成帶分數表示的全部種數。
注意:不要求輸出每個表示,只統計有多少表示法!

例如:
用戶輸入:
100
程序輸出:
11

再例如:
用戶輸入:
105
程序輸出:
6

資源約定:
峯值內存消耗(含虛擬機) < 64M
CPU消耗 < 3000ms

請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入…” 的多餘內容。

所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。
注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。
注意:主類的名字必須是:Main,否則按無效代碼處理。

解題思路

這是一個在 9 的全排列中放置 “ / ” 的問題

全排列是非常經典的了
所以解決的問題是 每當形成一個全排列時,我們還要根據題意來枚舉 第一個數的大小和“ / ” 的位置 所以用的枚舉思想 但每道題處理的還是有很大不同的


import java.util.Scanner;

/**
 * 
 * @author sjf666
 * 
 * 2020年4月13日下午3:46:03
 */


//根據題意 這是9的全排列然後通過枚舉 " / " 的位置來舉出符合題意的形式
public class Demo04_B2013_帶分數 {

	static int[] fp = new int[9];
	static int[] book = new int[10];
	static int ans;
	static int n;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		n = sc.nextInt();

		dfs(0);

		System.out.println(ans);
	}

	
	//進行全排列
	public static void dfs(int step) {
		
		if(step == 9) {
			if(check()) 
				ans++;
			return;
		}
			
		for(int i =1;i<=9;i++) {
			if(book[i] == 0) {	
				fp[step] = i;
				book[i] = 1;
				dfs(step+1);
				book[i] = 0;
			}	
		}
		
	}
	
	public static boolean check() {
		
		int t = n;
		int numCnt = 0;
		while(t != 0) {
			numCnt++;
			t/=10;
		}
		
		for(int i = 0; i < numCnt ; i++) {
			int sum = 0 , sums = 1;
			int temp = i;
			while(temp>=0) {
				sum+=fp[temp]*sums;
				sums*=10;
				temp--;
			}
			// " / "的位置
			for(int j = i+4; j<9;j++) {
				//計算
				int fz=0,fm=0,fzs=1,fms=1;
				for(int k = 8; k > i;k--) {
					if(k <= j) {
						fz+=fp[k]*fzs;
						fzs*=10;
					}
					else {
						fm+=fp[k]*fms;
					    fms*=10;
					}
				}
				//整數
				if(fz!=0 && fm!=0 && fz/fm == (float)fz/fm && fz/fm < n) {
					if(sum+fz/fm == n)
						return true;
				}
				
			}
		}
		return false;
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章