藍橋——Sticks(dfs+剪枝,POJ 1011)

試題 算法訓練 Sticks

資源限制

時間限制:1.0s   內存限制:999.4MB

  Sticks

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 113547   Accepted: 26078

問題描述

  George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.

輸入格式

  The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.

輸出格式

  The output should contains the smallest possible length of original sticks, one per line.

樣例輸入

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

樣例輸出

6
5

題目大意:這個人把一堆等長的木棍切割成n塊小木棍,後來他想把他們拼成同樣長度的木棍,但是他不知道原始的木棍長度是多少,也不知道原始木棍的數目,所以現在就問要把這一堆木棍拼成同等長度的大木棍,需要拼成木棍的最短的長度。

思路:用dfs把滿足的長度搜一遍,注意剪枝

剪枝:

1. 木棍符合結果的長度一定是總木棍長度的因數

2. 將木棍從大到小排序,則可以在比較少的次數裏合成想要的那種長度 

3. 在搜索過程中,如果前一個木棍沒有成功拼接,那麼後面與其相同的木棍也要被剪掉

4. 當一個木棍拼湊失敗時,直接回溯,不再按照這個條件浪費時間

 

代碼:

#include <bits/stdc++.h>
#define Max 101
using namespace std;
int sticks[Max],vis[Max];
int min_len; // 滿足條件的最小長度
int stick_num;//  木棍數量 
int n;// stick的數量
int total_len; // 木棍總長度
int cmp ( int a, int b){
	return a > b;
} 
/*
	sum 指當前拼湊的這根木棍的長度
	cur 指當前正在搜索的木棍下標 
	res 表示已經拼成的木棍的數量
	k 表示假設的單個木棍的長度   ->  min_len 
*/
bool dfs(int sum, int cur, int res, int k){
	if(res == stick_num){
		return true;
	}
	for(int i = cur; i < n; i++){
		//第i個被用了,或者與前一個木棍長度相同但是 前一個也沒被用 
		//那麼 這個也不能被用 
		if(vis[i] || (i && sticks[i] == sticks[i-1] && !vis[i-1])){
			continue;
		}
		if(sticks[i] + sum == k) {
			vis[i] = 1;
			if(dfs(0, 0, res+1, k)){
				return true;
			}
			vis[i] = 0; //雖然這步拼成了長度爲x的木棍,但是剩下的不能成功拼湊,所以失敗回溯 
			return false;
		}
		if(sticks[i] + sum < k) { //沒拼好 
			vis[i] = 1;
			if(dfs(sticks[i] + sum, i + 1, res, k)){
				return true;
			}
			vis[i] = 0;
			if(!sum) return false;
		}
	}
	return false;
} 
int main(){
	while(cin >> n && n) {
		total_len = 0;
		for(int i = 0; i < n; i++) {
			cin >> sticks[i];
			total_len += sticks[i];
		}
		//從大到小排序  可以在比較少的次數裏合成想要的那種長度 
		sort(sticks, sticks + n, cmp);
		int flag = 0;
		for(min_len = sticks[0]; min_len < total_len; min_len++){
			//因爲初始的木棍是等長的 
			if(total_len % min_len == 0) {
				memset(vis, 0, sizeof(vis));
				stick_num = total_len / min_len; // 可能的最多木棍數量 
				if(dfs(0,0,0,min_len)){
					cout << min_len << endl;
					flag =  1;
					break;
				}
			}
		} 
		if(!flag) {
			cout << total_len << endl;
		}
	}
	return 0;
}

 

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