hdu 1455 sticks【dfs】+经典剪枝

题目链接:https://vjudge.net/problem/HDU-1455

转载于:>>>>>>

题目大意:

George把一些等长的树枝切成了n个长度不超过50的短树枝,现在给你这些短树枝的长度,计算出原来树枝的最小长度。

解题分析:
以下是几种主要的剪枝:

1、这些树枝的原长度一定大于短树枝的最大长度,同时也是小树枝总长度的因子,这个作为初步剪枝。

2、把树枝从大到小排序,开始匹配一根新的树枝的时候,如果第一根就不符合结果,那么后面的结果一定也不符合,很重要的一步剪枝,决定了代码从TLE到0msAC。

3、排序后的树枝,如果当前树枝不满足,就跳过后面所有等长的树枝。

#include<cstdio>  
#include<cstring>  
#include<iostream>  
#include<algorithm>  
using namespace std;
int a[70], n, fp;
bool vis[70];
bool cmp(int a, int b) {
    return a>b;
}
void dfs(int pos, int len, int g, int num) {//当前下标、当前长度、目标长度、已匹配数量  
    if (fp)return;
    if (num == n) {//所有树枝都匹配上了,说明有解  
        fp = 1;
        return;
    }
    for (int i = pos; i<n; ++i) {
        if (!vis[i] && a[i] + len <= g) {
            vis[i] = 1;
            if (a[i] + len == g) {
                dfs(0, 0, g, num + 1);      //如果这跟木棍已经构建好了,则pos重置为0,从0开始重新遍历
            }
            else {
                dfs(i + 1, a[i] + len, g, num + 1);
            }
            vis[i] = 0;//去除标记  
            if (fp)return;//找到了结果,返回  
            if (len == 0)return;    //开始匹配一根新的树枝的时候,如果第一根就不符合结果,那么后面的结果一定也不符合
            while (i<n&&a[i + 1] == a[i])++i;//排序后的树枝,如果当前树枝不满足,就跳过后面所有等长的树枝。
        }
    }
}
int main() {
    int sum;
    while (scanf("%d", &n), n) {
        memset(vis, 0, sizeof(vis));
        sum = 0;
        for (int i = 0; i<n; ++i) {
            scanf("%d", &a[i]);
            sum += a[i];
        }
        sort(a, a + n, cmp);//从大到小排序,搜索的时候优先选择大的,减少冲突的情况  
        for (int i = a[0]; i <= sum; ++i) {
            if (i == sum)printf("%d\n", sum);//剪枝  
            else if (sum%i == 0) {//剪枝1  
                fp = 0;
                dfs(0, 0, i, 0);
                if (fp == 1) {
                    printf("%d\n", i);
                    break;
                }
            }
        }
    }
    return 0;
}

2018-05-25

猜你喜欢

转载自www.cnblogs.com/00isok/p/9091053.html