UVa 307 - Sticks

題目:已知一些等長的木棍切割后的小段,問能拼成最小的原始木棍組的長度。

分析:圖論、搜索、剪枝。回溯解題,不過需要很多剪枝。

            1.遞減排序小段減少搜索次數,并為其他的優化最準備;

            2.相同長度的前面小段沒有取,本段取了也沒用;

            3.一根木棍構成失敗,後面也不成立,那麼直接結束;

            4.搜索同一根木棍時,只會取當前取得的小段後面的小段;

說明:最開始以小段為基準不好剪枝,改成以木棍為基準╮(╯▽╰)╭。

#include 
#include 
#include 
#include 

using namespace std;

int stick[101], units[101], visit[101];

int dfs(int unintnow, int unintsize, int sticknow, int sticklen, int sticksize)
{
	if (sticknow >= sticksize) return 1;
	for (int i = unintnow; i < unintsize; ++ i) {
		//1: 相同的前面不取,这个也不取 
		if (visit[i] || (i && !visit[i-1] && units[i-1] == units[i])) continue;
		if (stick[sticknow]+units[i] > sticklen) continue; 
		visit[i] = 1;
		stick[sticknow] += units[i];
		if (stick[sticknow] == sticklen) {
			if (dfs(0, unintsize, sticknow+1, sticklen, sticksize)) return 1;
		}else if (stick[sticknow] < sticklen) {
			if (dfs(i+1, unintsize, sticknow, sticklen, sticksize)) return 1;
		}
		stick[sticknow] -= units[i];
		visit[i] = 0;
		//2: 拼第sticknow根时失败,则直接结束 
		if (stick[sticknow]+units[i] == sticklen || !stick[sticknow]) return 0;
	}
	return 0;
}

bool cmp(int a, int b)
{
	return a > b;
}

int main()
{
	int n;
	while (cin >> n && n) {
		int sum = 0, max = 0;
		for (int i = 0; i < n; ++ i) {
			cin >> units[i];
			sum += units[i];
			if (max < units[i])
				max = units[i];
			stick[i] = 0;
			visit[i] = 0;
		}
		
		sort(units, units+n, cmp);
		for (int l = max; l <= sum; ++ l) 
			if (sum%l == 0 && dfs(0, n, 0, l, sum/l)) {
				cout << l << endl;
				break;
			}
	}
    return 0;
}
測試數據:

64
40 40 30 35 35 26 15 40 40 40 40 40 40 40 40 40 40 40 40 40 40 
40 40 43 42 42 41 10 4 40 40 40 40 40 40 40 40 40 40 40 40 40 
40 25 39 46 40 10 4 40 40 37 18 17 16 15 40 40 40 40 40 40 40 
40

你可能感兴趣的:(解题报告,图论)