ACWing.167 Wooden stick DFS+pruning

ACWing.167 Wooden stick DFS+pruning

Title description

George took a set of wooden sticks of equal length and chopped them randomly so that the length of each stick did not exceed 50 units of length.

Then he wanted to restore these wooden sticks to the state before cutting, but forgot how many sticks there were at the beginning and the initial length of the sticks.

Please design a program to help George calculate the minimum possible length of the stick.

The length of each stick is represented by an integer greater than zero.

Input format

The input contains multiple sets of data, and each set of data includes two rows.

The first line is an integer not exceeding 64, indicating how many sections of sticks are in total after being cut.

The second line is the length of each section of the stick after truncation.

After the last set of data, there is a zero.

Output format

For each group of data, output the smallest possible length of the original wooden stick, and each group of data occupies one line.

data range

The data guarantee that the length of each section of wooden stick is not more than 50.

Input sample:

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample output:

6
5

Problem solving ideas

Obviously, you need to use explosive search to solve it, so the key lies in how to optimize pruning. The preparations required are as follows:

  1. An array stick: used to store the input of the question
  2. An array vis: record the visit to each stick
  3. Variable cnt: used to record the total number of sticks
  4. Variable len: used to find the legal length before dfs and record
  5. Variable group: number of groups
  6. Variable total: the total length of the record

The following analysis of problem-solving ideas:

  1. The original length of the stick is unknown, but the total length of all sticks is known, so we can enumerate the legal length of each "hypothesis" (divisible by the total length), and search to determine whether the length is truly legal. One thing to note here is that the legal length must be larger than the longest stick and shorter than all sticks, so it has reached the range where the legal length exists;
  2. Assuming that the legal length is determined, the number of small wooden sticks cnt=sum/len is also determined, then this can be used as the judging condition of the legal sign: when all the small wooden sticks are used up, the length of cnt is equal. Small wooden stick.
  3. dfs search ideas:
    1. Enumeration length len;
    2. Use small wooden sticks that have not been used before to piece together small wooden sticks;
    3. Determine whether the length plan is feasible.

Pruning and optimization:

  1. Set a fail variable when searching to mark the length of the sticks that failed to splice, to avoid repeated searches for sticks of the same length
  2. It is not easy to consider: when the stick can not be used at the beginning and the end, then the scheme fails. Therefore, timely judgment and processing should be performed when the search fails
  3. You can sort all the sticks at the beginning, from largest to smallest. If there is no match after filling in the longest, then this length is absolutely illegal. (Big blocks must be searched less frequently than small blocks)
  4. Limit the number of small sticks added to the sticks, and ensure that the length of the sticks added is decreasing (must be sorted first)

Code

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int stick[65];
bool vis[65];
int len, total, n, group;

inline bool cmp(const int &a, const int &b){
    return a > b;
}

bool dfs(int complete, int now, int done){
    if(complete > group) return true;
    if(now == len) return dfs(complete + 1, 0, 1);
    int fail = 0;
    for(int i = done; i <= n; i++){
        if(!vis[i] && now + stick[i] <= len && fail != stick[i]){
            vis[i] = true;
            if(dfs(complete, now + stick[i], i + 1)) return true;
            vis[i] = false;
            fail = stick[i];
            if(now == 0 || now + stick[i] == len) return false;
        }
    }
    return false;
}

int solve(){
    sort(stick + 1, stick + n + 1, cmp);
	for(int i = 1; i <= n; i++) total += stick[i];
    for(len = stick[1]; len <= total; len ++){
        if(total % len != 0) continue;
		group = total / len;
        memset(vis, 0, sizeof(vis));
        if(dfs(1, 0, 1)) return len;
		
    }
}

int main(){
    while(cin >> n){
		total = len = 0;
		memset(stick , 0, sizeof(stick));
		for(int i = 1; i <= n; i++) cin >> stick[i];
        if(n == 0) break;
        cout << solve() << endl;
    }
}

Guess you like

Origin blog.csdn.net/yanweiqi1754989931/article/details/109603322