2014 UESTC Training for Search Algorithm E

回溯+剪枝
对于每个被切开的木棍,只有2中状态要么选要么不选,于是想到回溯dfs方法
dfs的三个参数,当前已经使用过的木棍数量,从第几个木棍开始当前查找,当前和
回溯终点就是使用过的木棍数量等于N;
对于每次查找,如果sum+stick[i]<cur可以继续查找
如果刚好相等那么进行标记从头再查找是否可以凑成第二个完整木棍
剪枝:
1.应该从大到小排序,这样可以递归的次数
2.原完整木棒的长度必然是总分开长度的约束,而且必然大于等于切开后的木棍最长的那一块的长度
3.对于排序后长度相同的木块,相同长度的木块前面如果不选,那么相同长度的木棒一定不选
4.对于每一颗欲要组成的新的木棒,如果可利用的最大木块都大于cur,那么不可能形成木块

那么就是 if (sum==0) return false;

#include <map>
#include <set>
#include <list>
#include <cmath>
#include<cctype>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b)
{
	return a % b == 0 ? b : gcd(b, a % b);
}
int sticks[70];
int Min,Max;
int N;
int cur;
int vis[70];
int cmp(const int &a,const int &b)
{
    return a>b;
}
void init()
{
    Max=0;
    for (int i=0;i<N;i++)
    {
        scanf("%d",&sticks[i]);
        Max+=sticks[i];
    }
    sort(sticks,sticks+N,cmp);
    Min=sticks[0];
}
bool dfs(int num,int index,int sum)
{
    if (num==N)return true;
    for (int i=index;i<N;i++)
    {
        if (vis[i]) continue;//如果当前木条用过那么跳过
        if (i>=N) break;
        if (sum+sticks[i]<cur)//可能可以递归
        {
            vis[i]=1;
            if (dfs(num+1,i+1,sum+sticks[i])) return true;
            vis[i]=0;
            int j;
            for ( j=i;j<N;j++)
                if (sticks[j]!=sticks[i]) break;
            i=j-1;
        }
        else if (sum+sticks[i]==cur)
        {
            vis[i]=1;
            if (dfs(num+1,0,0)) return true;//合成一个约数,那么从头开始
            vis[i]=0;
            return false;
        }
        if (sum==0) return false;//针对每一颗新组成的完整木棍,如果当前最大值就大于CUR,那么不可能形成
    }
    return false;
}
int main()
{
    while (scanf("%d",&N)==1)
    {
        memset(sticks,0,sizeof(sticks));
        if (N==0) break;
        init();
        //printf("%d %d\n",Max,Min);
        cur=0;
       for (int i=N;i>0;i--)
       {
           if (Max%i==0 && Max/i>=Min)
           {
               memset(vis,0,sizeof(vis));
               cur=Max/i;
               //printf("%d\n",cur);
               if (dfs(0,0,0)) {printf("%d\n",cur);break;}
           }
       }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值