[原创]我的PKU ACM POJ 1020解答

[原创]我的PKU ACM POJ 1020解答

开始用的贪心法,有些数据不能过,后来发现网上说贪心法是不能用于这题的,还有一个反例如下:

1
10 14 1 1 1 1 1 4 4 3 3 3 3 3 3 3

答案是KHOOOOB!
用贪心法是无法解决上面的数据的。
因此,网上参照了DFS搜索弄出了一个AC的代码,基本思路就是从左上开始切,寻找某列已切行数最少的开始,然后从大到小逐个
试蛋糕,看是否能切出来,若当前切割失败,则回溯上一步,换个不同大小的继续试。切完需要的块数就表示刚好可以。

Source Code

Problem: 1020User: absolute
Memory: 204KTime: 32MS
Language: C++Result: Accepted
  • Source Code
    #include <stdio.h>
    #include <memory.h>
    int cakeside,piecenum,pieces[11];
    //fillednum stand for the nums had filled
    bool fill(int fillednum,int* used)
    {
        //如果已填的个数等于需求的蛋糕个数则表示刚好
        if(fillednum==piecenum)
            return true;
        int i,j,minusedrow=41,nowcol=0;
        //寻找未填的行数最小的那列
        for(i=1;i<=cakeside;i++)
        {
            if(used[i]<minusedrow)
            {
                minusedrow = used[i];
                nowcol = i;
            }
        }
        //从行数最小的那列开始,从大到小搜索能填入的蛋糕
        for(i=10;i>0;--i)
        {
            if(pieces[i]>0 && i+minusedrow<=cakeside+1 && i+nowcol<=cakeside+1)
            {
                bool flag=true;
                //判断连续的区域是否能放下当前蛋糕
                for(j=nowcol;j<nowcol+i;j++)
                {
                    if(used[j]>minusedrow)
                    {
                        flag=false;
                        break;
                    }
                }
                if(flag)
                {
                    //能放下则更新蛋糕所在的列的已填行数
                    for(j=nowcol;j<nowcol+i;j++)
                        used[j] += i;
                    //当前大小蛋糕数减一
                    pieces[i]--;
                    //继续切下一块蛋糕
                    if(fill(fillednum+1,used))
                        return true;
                    //到这说明上面方案不可行,回溯,不能切当前大小的蛋糕
                    pieces[i]++;
                    for(j=nowcol;j<nowcol+i;j++)
                        used[j] -= i;
                }
            }
        }
        return false;
    }
    int main()
    {
        int ncase,i,j;
        scanf("%d",&ncase);
        while(ncase>0)
        {
            --ncase;
            int sum=0;
            int pieceside;
            scanf("%d %d",&cakeside,&piecenum);
            memset(pieces,0,sizeof(pieces));
            //记录各不同大小的蛋糕个数,大小范围在1-10之间
            for(i=0;i<piecenum;++i)
            {
                scanf("%d",&pieceside);
                //大小为pieceside的个数
                pieces[pieceside]++;
                sum += pieceside*pieceside;
            }
            if(sum!=cakeside*cakeside)
            {
                printf("HUTUTU!\n");
                continue;
            }
            bool IsWaste=true;
            //used[i]记录的是第i列还没填的那行
            int used[41];
            for(i=1;i<=40;i++) used[i]=1;
            //fill表示从第几块蛋糕开始填是否能刚好填满所有蛋糕
            IsWaste = !fill(0,used);
            if(IsWaste)
                printf("HUTUTU!\n");
            else
                printf("KHOOOOB!\n");
    
        }
        return 0;
    }
    

转载于:https://www.cnblogs.com/absolute8511/archive/2009/04/26/1649589.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值