• pku 1020


    题意:就是用几个小正方形,去拼成个大的正方形。

    思路:从大到小,从左到右,深搜,不是很难,

    网上的代码很简洁,我就不用自己的了,加点注释吧

    #include <stdio.h>
    #include <memory.h>
    int cnt[20]; //记录长度为i的正方形个数
    int len[50]; //记录目前第i列覆盖长度
    int cake_side, npiece;
    bool chk(int used)
    {
    if(used == npiece) //所有正方形都用上了,返回真,跳出
    return true;
    int min = 100, ind = -1;
    for(int i = 0; i < cake_side; i++) //枚举大蛋糕边的长度
    if(min > len[i])
    {
    min = len[i]; /* 找目前覆盖最小的那一列 */
    ind = i; //标记标号
    }
    //先放大的后放小的
    for(int i = 1; i <= 10; i++)
    if(cnt[i] && len[ind] + i <= cake_side) //有i这个边长,加上刚才最小的覆盖,合起来的值小于等于大正方形的边长
    {
    int wid = 0;/* 放置宽为 i 的 */
    for(int j = ind; j < cake_side; j++) //检测宽度是否符合要求,即是否放得下边长为i的正方形
    if(len[j] == len[ind]) wid++;
    else break;
    if(wid >= i) //能放下
    {
    cnt[i]--; //在下一层递归中,i用掉了一个
    for(int j = ind; j < ind + i; j++) //从ind到i+ind列覆盖的值更新,进入下一层递归
    len[j] += i;
    if(chk(used + 1)) //used表示用的正方形数
    return true;
    for(int j = ind; j < ind + i; j++) //更新值变回来,继续循环,不影响下次枚举
    len[j] -= i;
    cnt[i]++; //同上
    }
    }
    return false;
    }
    int main()
    {
    int cs = 0;
    scanf("%d", &cs);
    while(cs--)
    {
    memset(len, 0, sizeof(len));
    memset(cnt, 0, sizeof(cnt));
    int area = 0;
    scanf("%d %d", &cake_side, &npiece);
    for(int i = 0; i < npiece; i++)
    {
    int side;
    scanf("%d", &side);
    cnt[side]++;
    area += side * side;
    }
    if(cake_side * cake_side == area && chk(0))
    printf("KHOOOOB!\n");
    else
    printf("HUTUTU!\n");
    }
    return 0;
    }
  • 相关阅读:
    BZOJ 1202: [HNOI2005]狡猾的商人( 差分约束 )
    BZOJ 1800: [Ahoi2009]fly 飞行棋( 枚举 )
    BZOJ 2006: [NOI2010]超级钢琴( RMQ + 堆 )
    BZOJ 1029: [JSOI2007]建筑抢修( 贪心 )
    FZU 2233 ~APTX4869 贪心+并查集
    FZU2232 炉石传说 最大匹配
    FZU 2237 中位数 主席树 树上k大
    CodeForcesGym 100753B Bounty Hunter II 二分图最小路径覆盖
    NOIP2010关押罪犯 二分+二染色
    POJ2236 Wireless Network 并查集
  • 原文地址:https://www.cnblogs.com/FreeAquar/p/2155215.html
Copyright © 2020-2023  润新知