拯救少林神棍 代码有注释


拯救少林神棍

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <memory.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <functional>   // std::greater

using namespace std;
int T, N;
int L;
int nLastStickNo;//最近拼上去的那条木棒的下标
vector<int> anLength;
int anUsed[65];//是否用过的标记
int i, j, k;
int Dfs(int R, int M);
int main()
{ 
	while (1) {
		cin >> N;
		if (N == 0)
			break;
		int nTotalLen = 0;
		anLength.clear();
		for (int i = 0; i < N; i++) {
			int n;
			cin >> n;
			anLength.push_back(n);
			nTotalLen += anLength[i];
		}
		sort(anLength.begin(), anLength.end(), greater<int>());
		//从最长的第一根小棒开始,直到总长度的一半  
		for (L = anLength[0]; L <= nTotalLen / 2; L++) {
			if (nTotalLen % L)//如果不可以全拼完 ,L长度就不是
				continue;
			memset(anUsed, 0, sizeof(anUsed));
			if (Dfs(N, L)) {
				cout << L << endl;
				break;
			}
		}
		if (L > nTotalLen / 2)//如果大于小棒总长度的一半  输出总长度
			cout << nTotalLen << endl;
	} // while 
	return 0;
} 
//nUnusedSticks 还剩小棍数量
int Dfs(int nUnusedSticks, int nLeft)
// nLeft表示当前正在拼的棍子和 L 比还缺的长度
{
	if (nUnusedSticks == 0 && nLeft == 0)
		return true;
	if (nLeft == 0) //一根刚刚拼完
		nLeft = L;  //开始拼新的一根
	int nStartNo = 0;
	if (nLeft != L) //剪枝4
		nStartNo = nLastStickNo + 1;//nLastStickNo  最近拼上去的那条木棒的下标
	for (int i = nStartNo; i < N; i++) {//遍历所有小棍
		if (!anUsed[i] && anLength[i] <= nLeft) {//没有被使用过且 小于棒子还差的长度
			if (i > 0) {//不是第一根
				if (anUsed[i - 1] == false 
					&& anLength[i] == anLength[i - 1])//前一根没有被使用 且长度一样
					continue; //剪枝1
			}
			anUsed[i] = 1;  nLastStickNo = i;
			if (Dfs(nUnusedSticks - 1,
				nLeft - anLength[i]))
				return true;
			else {
				anUsed[i] = 0;//说明本次不能用第i根
							  //第i根以后还有用

				if (anLength[i] == nLeft || nLeft == L)
					return false;//剪枝3、2
			}
		}
	}
	return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值