POJ 1011 (DFS+剪枝)

POJ 1011

题目意思给你n个数,大于50的不算。让你把这n个数分成m组,每组的长度相同为len,使得这个len最短

光用dfs写会超时,剪枝要剪很多方面

1:优化搜索顺序 把木棍从大到小排序,优先尝试长的木棍

2:排除等效冗余

  1.当上一个搜索失败了,下一个的数若等于上一个失败的数,那么一定失败

  2.如果在当前木棒中尝试拼第一根木棍的递归分支就失败,那么直接判断当前分支失败,立即回溯

  3.限制先后加入一

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <iomanip>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#include <vector>
//const int maxn = 1e5+5;
#define ll long long
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}

#define MAX INT_MAX
#define FOR(i,a,b) for( int i = a;i <= b;++i)
#define bug cout<<"--------------"<<endl
using namespace std;
bool cmp(int a,int b)
{
    return a>b;
}
int cnt,sum,maxx,len,n;
int vis[500],a[500];

int dfs(int k,int cab,int last)// last排除等效冗余3
{
    if(k > cnt)
    {
        return true;
    }
    if(cab==len)
    {
        return dfs(k+1, 0 ,1);
    }
    int fail=0;   //         排除等效冗余1
    for(int i=last;i<=n;++i)   // last排除等效冗余3
    {
        if(vis[i]==0 && cab+a[i]<=len &&fail!=a[i])
        {
            vis[i]=1;
            if(dfs(k,cab+a[i],i+1))
                return true;
            fail=a[i];
            vis[i]=0;
            if (cab==0 || cab+a[i]==len)//如果cab为0,或者相加正好是len,但是失败了,那么一定是失败了.//排除等效冗余2
                return false;
        }
    }
    return false;
}
int main()
{
    ios::sync_with_stdio(false);
//    freopen("D:\\common_text\\code_stream\\in.txt","r",stdin);
//    freopen("D:\\common_text\\code_stream\\out.txt","w",stdout);
    while(cin>>n && n)
    {
        int x=0,hhh=0;
        memset(vis,0,sizeof(vis));
        sum=0;
        maxx=0;
        cnt=0,len;

        FOR(i,1,n)
        {
            cin>>x;
            if(x<=50)
            {
                hhh++;
            }
            a[hhh]=x;
            sum+=x;
            maxx=max(maxx,x);
        }
        n=hhh;



        sort(a+1,a+1+n,cmp);
        for(int i=maxx;i<=sum;i++)  //changdu
        {
            if(sum%i==0)
            {
                //cout<<i<<" "<<cnt<<" "<<endl;
                len=i;
                cnt=sum/i;
                 memset(vis,0,sizeof(vis));
                if(dfs(1,0,1)==1)
                    break;
            }
        }

        cout<<len<<endl;
    }


}

 

根原始木棒的长度是递减的(先加入x后加入y和先加入y后加入x是等效的,只需要搜索其中一种)

posted @ 2019-07-30 19:13  阿斯水生产线  阅读(186)  评论(0编辑  收藏  举报