poj 1011 Sticks(dfs)

【题目大意】:一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。计算这组原始木棒的可能最小长度。


【解题思路】:明显的dfs。注意下面几点。

1.组合木棒时优先选择长的木棍。
2.木棒的长度一定是所有木棍长度的和的约数。
4.长度相同的两根木棒,前面的一根没被组合,后面的一根也无法被组合。
5.如果此次是在尝试第i个木棒的第一段,最大的切割下来的木棒组合不成功,则直接退回去。


【代码】:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
                   
using namespace std;
                   
#define eps 1e-8
#define pi acos(-1.0)
#define inf 1<<30
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long

int n,sum,ans;
int len[100];
int vis[100];

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

bool solve_dfs(int anss,int now,int j,int cnt){
    if (anss*cnt==sum) return true;
    for (int i=j; i<n; i++){
        if (vis[i]==1) continue;
        if (len[i]==len[i-1] && !vis[i-1]) continue;
        if (now+len[i]==anss){
            vis[i]=1;
            if (solve_dfs(anss,0,0,cnt+1)) return true;
            vis[i]=0;
            return false;
        }
        else{
            if (now+len[i]<anss){
                vis[i]=1;
                if (solve_dfs(anss,now+len[i],i+1,cnt)) return true;
                vis[i]=0;
                if (now==0) return false;
            }
        }
    }
    return false;
}

int main() {
    while (~scanf("%d",&n)){
        if (n==0) break;
        sum=0;
        for (int i=0; i<n; i++){
            scanf("%d",&len[i]);
            sum+=len[i];
        }
        ans=-1;
        sort(len,len+n,cmp);
        for (int i=len[0]; i<sum; i++){
            if (sum%i!=0) continue;
            memset(vis,0,sizeof(vis));
            if (solve_dfs(i,0,0,0)) {
                ans=i;
                break;
            }
        }
        if (ans==-1) ans=sum;
        printf("%d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值