HDU1455 Sticks(DFS+剪枝)

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


思路:DFS,搜索的时候记录下每个树枝是否被匹配过,搜索的数据包括当前已经匹配的长度、目标长度、已经匹配的树枝数。剪枝很重要:

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

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

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


#include<bits/stdc++.h>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF  0x3f3f3f3f
typedef long long  LL;
int a[70],n,f;
bool vis[70];
bool cmp(int a,int b){
    return a>b;
}
void dfs(int pos,int len,int g,int num){//当前下标、当前长度、目标长度、已匹配数量
    //printf("dfs: %d %d %d %d\n",pos,len,g,num);
    if(f)return;
    if(num==n){//所有树枝都匹配上了,说明有解
        f=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);
            }else{
                dfs(i+1,a[i]+len,g,num+1);
            }
            vis[i]=0;//去除标记
            if(f)return;//找到了结果,返回
            if(len==0)return;//剪枝2,很关键!
            while(i<n&&a[i+1]==a[i])++i;//剪枝3
        }
    }
}
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
                f=0;
                dfs(0,0,i,0);
                if(f==1){
                    printf("%d\n",i);
                    break;
                }
            }
        }
    }
}

最初的代码还是各种奇葩错误,强大的逻辑和优秀的剪枝很关键,以后应该更多练习!

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值