POJ 1011

//代码比较长,好在逻辑比较清晰吧
//调bug调了挺久,错在 我直接返回false,未回撤对visit的修改。因为在当前情况下不可行,不代表其他深搜路劲不行
#include <cstdio>
#include <algorithm>
#include <cstring>

using std::sort;
using std::memset;

int n;
const int MAX = 70;
int stick[MAX];
bool visit[MAX];

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

bool match(int singlelength, int remain, int startindex, int matchnum)
{
    if(matchnum == n)
    return true;

    if(remain == singlelength)//剪枝2:重拼一个木棍的时候,只需要看第一个要匹配的能不能成功
    {
        while(visit[startindex] && startindex< n) startindex++;

        if(remain == stick[startindex])
        {
            visit[startindex] = true;
            if( match(singlelength, singlelength, 0, matchnum+1))
            return true;
            visit[startindex] = false;
        }
        else
        {
            visit[startindex] = true;
            if(match(singlelength, remain-stick[startindex], startindex, matchnum+1))
            return true;
            visit[startindex] = false;
        }
    }
    else
    {
        int same1 = -1;//剪枝3:相同的木棍,如果不行,不需要重试。
        for(int i = startindex ; i < n; i++)
        {
            if(visit[i] || same1 == stick[i])
            continue;

            if(remain < stick[i])
            continue;

            if(remain == stick[i])
            {
                visit[i] = true;
                if(match(singlelength, singlelength, 0, matchnum +1))
                    return true;
                else
                    same1 = stick[i];
                visit[i] = false;
            }
            else{
                visit[i] = true;
                if(match(singlelength, remain-stick[i], i, matchnum+1))
                    return true;
                else
                    same1 = stick[i];
                visit[i] = false;
            }
        }
    }
    return false;
}

int main()
{
    while(scanf("%d",&n)&&n)
    {
        int maxlength = 0;
        int sumlength = 0;

        memset(visit, 0, sizeof(visit));

        for(int i= 0 ; i < n; i++)
        {
            scanf("%d",&stick[i]);
            if(maxlength < stick[i])
            maxlength = stick[i];

            sumlength += stick[i];
        }

        sort(stick, stick+n, cmp);

        bool flag = false;
        //剪枝1:只有sumlength的约数才有可能成为dividelength,这里dividelength表示拼成的木棍长
        for(int dividelength = maxlength; dividelength <= sumlength; dividelength ++)
        {
            if(sumlength % dividelength)
            continue;

            memset(visit, 0, sizeof(visit));

            if(match(dividelength, dividelength, 0, 0))
            {
                printf("%d\n",dividelength);
                flag = true;
                break;
            }
        }
    }
    return 0;
}



posted @ 2013-07-02 20:18  little_hsu  阅读(287)  评论(0编辑  收藏  举报