题意
题目的大意呢是说有一堆长短不一的小棍,它们由原来若干根长度相同木棍截断而成,要求原来木棍的最短长度。
分析
这是一道比较典型的深度搜索题,原来的木棍长度最小可能是当前小棍里的最长值,所以先对小棍进行从大到小的排序, max(s1,s2,s3…sn) <= 原长度 <= sum(s1,s2,s3…sn)。
这里面要注意的是不要对相同长度的小棍进行重复搜索,那样必定超时。
这里采用了一个结构体,里面记录了下一个长度不同的小棍位置,这样得以减小搜索量。
代码如下:
Memory: 232K Time: 32MS Length:80LINES
#include<iostream>
#include<algorithm>
using namespace std;
struct Stick
{
int Length;
bool IsUsed;
int Next;
};
bool Compare(const Stick&s1, const Stick&s2) { return s1.Length > s2.Length; }; //从大到小排序
void Construct(Stick* StickArray, const int& Count) //计算下一个长度不同的位置
{
for (int i = 0; i < Count; ++i)
{
for (int j = i + 1; j < Count; ++j)
{
if (StickArray[i].Length != StickArray[j].Length)
for (; i < j; ++i) StickArray[i].Next = j;
}
StickArray[i].Next = Count;
}
};
int NextNotUsed(const Stick* StickArray, int Current, const int& Count) //找到下一个还未选取的小棍
{
while (Current < Count&&StickArray[Current].IsUsed) ++Current;
return Current;
}
int RemSum(const Stick* StickArray, const int& Count, int Start)//计算从当前位置开始的剩余小棍长度和
{
int Sum = 0;
for (; Start < Count; Start = NextNotUsed(StickArray, Start + 1, Count))
Sum += StickArray[Start].Length;
return Sum;
}
bool RecurSearch(Stick* StickArray, int Remain, const int& Count, int RemLength, const int& AssumeLength, int FirNotUsed)
{
if (Remain == 0 && RemLength == 0) return true; //选取完成
if (RemLength == 0) //假定的一根原木棍已经匹配完,再次赋值接着搜索
{
RemLength = AssumeLength;
FirNotUsed = NextNotUsed(StickArray, 0, Count);
}
for (int i = FirNotUsed; i < Count; i = NextNotUsed(StickArray, StickArray[i].Next, Count))
{
if (RemLength > RemSum(StickArray, Count, i)) return false; //已经大于后面未选取的小棍和
if (RemLength >= StickArray[i].Length)
{
StickArray[i].IsUsed = true;
if (RecurSearch(StickArray, Remain - 1, Count, RemLength - StickArray[i].Length, AssumeLength, NextNotUsed(StickArray, i, Count))) return true;
StickArray[i].IsUsed = false;
if (RemLength == AssumeLength || RemLength == StickArray[i].Length) return false; //已经失败,不用接着搜索
}
}
return false;
};
int Calculate(Stick* StickArray, const int& Count, const int& Sum)
{
int AssumeLength = StickArray[0].Length;
for (; AssumeLength != Sum; ++AssumeLength)
if (Sum%AssumeLength == 0 && RecurSearch(StickArray, Count, Count, AssumeLength, AssumeLength, 0)) break;
return AssumeLength;
};
int main()
{
int Count = 0;
while (cin >> Count&&Count != 0)
{
Stick StickArray[64];
int Sum = 0;
for (int i = 0; i < Count; ++i)
{
cin >> StickArray[i].Length;
Sum += StickArray[i].Length;
StickArray[i].IsUsed = false;
}
stable_sort(StickArray, StickArray + Count, Compare);
Construct(StickArray, Count);
cout << Calculate(StickArray, Count, Sum) << endl;
}
return 0;
}