uva 307 Sticks

刚开始在poj过了,拿到uva居然超时。改了好久都没成功,最后问了一个同学,稍微改了一下思路才ac。给uva数据跪了,电费不要钱吗?


这题数据太恶心,所以必需剪枝。


1.将数据从大到小排序,方便后面选择和操作。

2.最后答案只能是sum的约数,所以枚举范围最小为最长的那个棍子的长度,最大只需要到sum/2,如果前面没有求出答案,那么就是sum了。

3.在深搜过程中,如果当前棍子没有用上,下一个棍子如果长度一样,不用再试。

4.各种异常情况返回。

#include "stdio.h"
#include "string.h"
#include "algorithm"
using namespace std;

int a[70],u[70],ans,n,s;
bool flag;

bool cmp(int x,int y)
{
    return x>y;
}

void dfs(int num,int st,int len)
{
    int i;
    if(num==s) {flag=1;return;}
    if(flag) return;
    for(i=st;i<n;i++)
    {
        if(!u[i])
        {
            u[i]=1;
            if(a[i]+len<ans) dfs(num,i+1,a[i]+len);
            else if(a[i]+len==ans) dfs(num+1,0,0);
            u[i]=0;//恢复现场
            if(!st||a[i]==ans||a[i]+len==ans) return;//4对各种可以继续搜索下去的,却反回了的剪枝。没有这一步会超时
            while(a[i+1]==a[i]) i++;//3中剪枝
        }
    }
    return ;
}

int main()
{
    int i,sum;
    while(~scanf("%d",&n))
    {
        if(n==0) break;
        sum=0,flag=0;
        for(i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        sort(a,a+n,cmp);//从大到小排序
        for(ans=a[0];ans<=sum/2; ans++)
        {
            if(sum%ans==0)
            {
                s=sum/ans;
                memset(u,0,sizeof(u));
                dfs(0,0,0);
                if(flag==1) break;
            }
        }
        if(ans>sum/2) printf("%d\n",sum);
        else printf("%d\n",ans);
    }
    return 0;
}


poj ac代码

#include "stdio.h"
#include "string.h"
#include "algorithm"
using namespace std;

int a[70],u[70],ans,n;

bool cmp(int x,int y)//sort排序用的
{
    return x>y;
}

bool dfs(int num,int len,int st)
{
    if(num==n) return 1;//全部的棒子都实用了
    else if(len==ans) return dfs(num,0,0);
    else
    {
        int i,t;//t记录ai-1,剪枝,如果相等的棒子第一个没用,后面也不去用
        for(t=0,i=st;i<n;i++)
            if(!u[i]&&len+a[i]<=ans&&t!=a[i])//可以使用
            {
                t=a[i],u[i]=1;
                if(dfs(num+1,len+a[i],i+1)) break;
                u[i]=0;//恢复现场
                if(st==0) return 0;//如果遍历了一遍后,为找到ai,当前ans错误,返回
            }
            if(n==i) return 0;//如果遍历了一遍后,为找到ai,当前ans错误,返回
            else return 1;
    }
}

int main()
{
    int i,sum;
    while(~scanf("%d",&n))
    {
        if(n==0) break;
        sum=0;
        for(i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        sort(a,a+n,cmp);//从大到小排序

        //从最长的棒子开始遍历,最大为sum
        for(ans=a[0]; ans<sum; ans++)
        {
            if(sum%ans==0)//ans肯定能被sum整除
            {
                memset(u,0,sizeof(u));//数组清零,0为未用,1为已用
                if(dfs(0,0,0))
                break;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}



你可能感兴趣的:(uva 307 Sticks)