poj1020(非常经典的dfs,易理解,难写代码)

60 篇文章 0 订阅

把二维降到一维,有助于操作

本题是用列的累积表达整个区域

例如在2~3列放一个大小为三的蛋糕,visit【i】++;(1<i<=4)

然后就是寻找比较好的位置进行放蛋糕。

放蛋糕的时候又要注意判断是不是可以放的下

对于成功放入的进行下一步搜索,否则回溯,这里可以把回溯的概念理解清楚


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int s,n;
int a[15];
int visit[50];

bool dfs(int num)
{
    if(num==n)
        return true;
    //寻找格子空位最多的,左优先
    int pos,minx=50;
    for(int i=1;i<=s;i++)
        if(minx>visit[i]){
            minx=visit[i];
            pos=i;
        }

    //枚举不同大小的蛋糕(从大到小)
    for(int i=10;i>0;i--){
        if(!a[i])
            continue;//去除为0的大小的蛋糕

        //检查范围(i大小的蛋糕是否超出范围)
        if(s-visit[pos]>=i&&s-pos+1>=i){
            /*下面检查盒子从第pos列到第pos+i-1列,共i列的宽度wide中
            是否每列剩余的空间都足够放入高度为i的蛋糕*/
            int wide=0;
            for(int j=pos;j<=pos+i-1;j++){
                if(visit[j]<=visit[pos]){
                    wide++;
                    continue;
                }
                break;
            }

            if(wide>=i)//成功放入
            {
                a[i]--;
                for(int j=pos;j<=pos+i-1;j++)
                    visit[j]+=i;

                if(dfs(num+1))
                    return true;

                //回溯
                a[i]++;
                for(int j=pos;j<=pos+i-1;j++)
                    visit[j]-=i;
            }
        }
    }
    return false;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        //初始化一切
        scanf("%d%d",&s,&n);
        memset(a,0,sizeof(a));
        memset(visit,0,sizeof(visit));


        //开始处理输入的数据
        int coun=0,temp,area=0;
        for(int i=0;i<n;i++){
            scanf("%d",&temp);
            a[temp]++;//合并可以减少排序

            area+=temp*temp;
            if(temp>s/2)
                coun++;
        }
        //减枝
        if(coun>1||area!=s*s){
            printf("HUTUTU!\n");
            continue;
        }

        if(dfs(0))
            printf("KHOOOOB!\n");
        else
            printf("HUTUTU!\n");
    }
    return 0;


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值