Luo Gu P1120 small wooden dfs + pruning

Problem Description

[Link title] https://www.luogu.com.cn/problem/P1120
George has some of the same long small wooden sticks, wooden poles which he freely cut into several sections, each section is not long until more than 50.
Now, he wants a small wooden stick together into its original appearance, but they forget how much stick and their lengths when he started.
Given the length of each segment of a small wooden stick, programming help him find the smallest possible length of the original wooden sticks.

Input

A total of two lines.
The first line of a single integer N represents the total number of small stick cut through after which the N≤65

Output

The minimum possible length of a number representing the requirements of the original stick

Sample Input

9
5 2 1 5 2 1 5 2 1

Sample Output

6

Analysis of ideas

Enumerate every possible length, the longest from the start, to stick length and (a)
pruning very, very critical
I think the most important pruning, the card is my oldest pruning if(len == 0 || aim-len == a[i]) return false;
mainly analyze this Again, when the execution of this sentence explain what? description back, while back then what if the explanation that the foregoing description dfs does not return true, len back back to 0 when the time, indicating the beginning of this election stick, fight not aim length, then there is no need to search, and the other is when len+a[i] == aimno returns true, that there is no need to search the
other pruning looking at the code it

Accepted code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <vector>
#include <queue>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define cin(a) scanf("%d",&a)
#define pii pair<int,int>
#define ll long long
#define gcd __gcd
const int inf = 0x3f3f3f3f;
const int maxn = 100;
int n,m,t,sum,aim; //t是有效木棍根数,sum是木棍总长度,aim是目标长度
int a[maxn];                //木棍长度
bool vis[maxn];

bool dfs(int cnt,int len, int pos)  //还要拼的根数,拼了的长度,以及下标
{
    if(cnt == 1) return true;          //拼成功了
    if(len == aim) return dfs(cnt-1,0,0);

    for(int i = pos; i < t; i++)          //a从小到大排序
    {
        if(!vis[i] && len+a[i] <= aim)      //选取长度不超过aim的
        {
            vis[i] = 1;
            if(dfs(cnt,len+a[i],i+1)) return true;
            vis[i] = 0;                     //回溯
            if(len == 0 || aim-len == a[i]) return false;   //拼失败了
            while(i+1 < n && a[i+1] == a[i]) i++;       //长度一样的没必要重复搜索
        }
    }
    return false;
}

int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    scanf("%d",&n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d",&m);
        if(m <= 50)
        {
            a[t++] = m;
            sum += m;
        }
    }
    sort(a,a+t,greater<int>());         //从大到小排序
    int ans = 0;
    for(int i = a[0]; i <= sum; i++)    //i是枚举长度
    {
        if(sum%i == 0)        //dfs能被sum整除的i
        {   
            for(int i = 0; i < t; i++) vis[i] = 0;
            aim = i;                //要拼的长度
            if(dfs(sum/i,0,0)) 
            {   
                ans = i;
                break;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

Guess you like

Origin www.cnblogs.com/hezongdnf/p/11993166.html