HDU1455:Sticks(DFS)

Sticks
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 14759 Accepted Submission(s): 4548

Problem Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.

Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.

Output
The output file contains the smallest possible length of original sticks, one per line.

Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

Sample Output
6
5

题目可以转化为又一堆棍子,把他们拼成相同长度的好几个,问这个长度最小是多少。

这个我做的第一个带返回值的dfs,关键是查找位置问题和剪枝问题。
查找问题:

  1. 若正好达到目标,则从头开始找。
  2. 若没达到,小于目标,则接着找。

剪枝问题:

  1. 若第一根棒子没法选,那就直接返回0(false)
  2. 若之后的棒子和这个棒子(回溯回来没法选的)一样长,那肯定也没法选,就跳过。
  3. 若总长度 % 目标长度不是0, 那肯定不可能拼成。

下面附上ac代码:

#include <bits/stdc++.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define INF 0x7ffffff
#define mod 10000019
typedef long long int ll;
int n,sum,realcnt;
struct node {
    int len;
    bool mark; //记录是否被用过
}record[100];
bool cmp(node a, node b) {
    return a.len > b.len;
}
int dfs(int cnt, int nowlen, int goal, int step) {
    if(cnt == realcnt) {
        return 1;
    }
    for(int i = step; i < n; i++) { //i = step:前面已经选过了 就不用看了
        if(record[i].mark == false && record[i].len + nowlen <= goal) {
            if(record[i].len + nowlen == goal) {
                record[i].mark = true;
                if(dfs(cnt + 1, 0, goal, 0)) {//不存在第一个棒子不取的问题(因为已经取成功了)
                    return 1;           //从头开始找
                }
                record[i].mark = false; //回溯
                while(record[i].len == record[i + 1].len) {
                    i++;
                }
            }
            else if(record[i].len + nowlen < goal) {
                record[i].mark = true;
                nowlen += record[i].len;
                if(dfs(cnt, nowlen, goal, i + 1)) {
                    return 1;              //这个是顺着继续找
                }
                nowlen -= record[i].len;
                record[i].mark = false;
                if(nowlen == 0) {
                    return 0; //下一个
                }
                while(record[i].len == record[i + 1].len && i + 1 < n) { //这个小于n要写上去!
                    i++; //因为最后还因为for循环i又会加1
                }
            }
        }
    }
    return 0;//一定要写 全部枚举过不符合就退出
}
int main() {
    while(cin >> n) {
        if(n == 0) {break;}
        sum = 0;
        for(int i = 0; i < n; i++) {
            cin >> record[i].len;
            sum += record[i].len;
            record[i].mark = false;
        }
        sort(record, record + n, cmp);
        for(int i = record[0].len; i <= sum; i++) {
            if(sum % i == 0) {
                realcnt = sum / i;
                if(dfs(0, 0, i, 0)) {
                    cout << i << endl;
                    break;
                }
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43555854/article/details/87935134