洛谷1120小木棍

题目描述:

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入输出格式输入格式:

输入文件共有二行。第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65(管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)第二行为N个用空个隔开的正整数,表示N根小木棍的长度。输出格式:输出文件仅一行,表示要求的原始木棍的最小可能长度

输入输出样例

输入样例#1:95 2 1 5 2 1 5 2 1

输出样例#1:6

---------------------------

各种剪枝

基本思路:

从小到大遍历原来木棍可能的长度

把木棍排序,按从大到小的顺序填入原来的木棍中.

具体剪枝直接看代码

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxN = 65;
int n;
int a[maxN];
int vis[maxN];
int DFS(int lim, int len, int cnt, int last)
{
    if(len == lim)
        len = 0, last = n - 1;
    if(cnt == n)
        return 1;
    int flag = 0;
    for(int i = last; i >= 0; i --)	//last用于剪枝  
        if(! vis[i] && a[i] + len <= lim)
        {
        	if(i < n - 1 && a[i] == a[i + 1] && ! vis[i + 1])	//剪枝
            	continue;
            vis[i] = 1;
            if(DFS(lim, len + a[i], cnt + 1, i))
                return 1;
            vis[i] = 0;
            if(len == 0 || a[i] == lim - len)
            //剪枝.对于一个原长度,假如它是可行的  
            //则当其为空的时候,第一位无论填入什么,都应该是可以成立的.假如第一位填入的就不成立,可直接退出
            //假如当前长度等于剩余长度且不可行,则其后的填法肯定都不可行  
            	return 0;
        }
    return 0;
}
int main()
{
    scanf("%d", &n);
    int sum = 0;
    for(int i = 0; i < n; i ++)
    {
        scanf("%d", &a[i]);
        if(a[i] > 50)
            i --, n --;
        else
            sum += a[i];
    }
    sort(a, a + n);
    for(int i = a[1]; i <= sum / 2; i ++)
        if(sum % i == 0)	//剪枝
        {
            memset(vis, 0, sizeof(vis));
            if(DFS(i, 0, 0, n - 1))
            {
                printf("%d", i);
                return 0;
            }
        }
    printf("%d", sum);
} 


原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6402883.html