http://acm.hdu.edu.cn/showproblem.php?pid=1455
题意:
给你n个小木棒,问他们能不能拼接成相同的长度,长度最小是多少
思路:
对于n个小木棒,从大到小排序
1.n个小木棒的长度和一定整除与拼接的长度 sum % L == 0
2.拼接的长度大于等于最大长度的小木棒 L >= a[1]
3.对于一个不可行的长度k,那么相同的k不在遍历
比如 5, 4,4,3
DFS先是搜到了(5,4。。。),发现这个方案不成立,那么根据DFS的性质,向前回溯,
搜到了下一个4,那么根据以前的经验,这个4也是不行的」
即对于一个k如果前面有一个未用的k,那么它也是不行的
4.如果一根木棒不能作为长度为L的一根木棒的一部分,那么这个方案L是不可行的,因为每一根小木棒都应该是各自大木棒的一部分,
因为一根大木棒的开始是以降序选择小木棒的,所以一根小木棒开始一根大木棒时,其他的大木棒无法完成,那么把开头的小木棒替换成其他小木棒也无济于事
举例:
left表示这跟木棒还剩多少长度,L是长度为L的方案
10, 9, 2, 4,5 ,sum 为30
从10开始遍历,10可行,9 无法组成10,(即left == L)时,无法成立
9,8,5,4,2,2, sum为30
9无法组成10,(left == L)无法成立
9,8,5,4,1,3, sum为30
9 + 1 == 10,可看成(a[i] == L,仅针对最后一根大木棒的最后一部分)或者(left == L 以a[i] 开头)后续无法组成10,无法成立,
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <string.h>
#include <queue>
#include <stack>
#include <deque>
#include <stdlib.h>
#include <bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
const int INF = 0x3f3f3f3f;
const int maxn = 50 + 5;
const int eps = 1e-8;
const int M = 1e9 + 7;
int pile[maxn];
int a[maxn];
int n;
bool cmp(int a, int b) {
return a > b;
}
bool vis[maxn];
int L;
bool dfs(int m, int left){
if(!m && !left)
return 1;
if(left == 0)
left = L;
for(int i = 1; i <= n; i ++) {
if(!vis[i] && a[i] <= left) {
if(i > 1)
if(!vis[i - 1] && a[i] == a[i - 1]) // 如果以前相同长度的未用,那么这个也不可用
continue;
vis[i] = 1;//用了
if(dfs(m - 1, left - a[i]))//dfs
return 1;
else {
vis[i] = 0;
if(left == L)//表示以a[i]开始一根木棒,但是它的其他木棒无法完成,那么这个方案无法成立
return 0;
}
}
}
return 0;
}
int main(int argc, const char * argv[]) {
while (scanf("%d", &n) && n) {
int sum = 0;
for (int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
pile[a[i]] ++;
sum += a[i];
}
sort(a + 1, a + 1 + n, cmp);
for (L = a[1]; L <= sum / 2; L ++) {
if(sum % L) continue;
memset(vis, 0, sizeof(vis));
if(dfs(n, L)) {
printf("%d\n", L);
break;
}
}
if(L > sum / 2)
printf("%d\n", sum);
}
return 0;
}