UVA-12113 重叠的正方形 题解答案代码 算法竞赛入门经典第二版

GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版

不太难的一道题目。

在一个4*4格子里面叠正方形,看看用6个能不能叠出这个图形。虽然输入的形式有点奇怪,但是不难处理,直接使用即可。以当前图形作为状态,一个方形一个方形的减去,看6个以内能不能减到空。

注意,第一个减去的正方形必定是个完整的正方形。还有正方形重叠后,有一部分边是会被盖住的,因此我们当前减去的正方形,就是按之前顺序盖住的正方形,因此这个正方形上方应该是没有东西的,即正方形内部应该是空的。

AC代码

#include <stdio.h>
#include <string.h>

// 1 横线 2 竖线
int map[5][9];
int mapt[7][5][9];
int spuare[8][3] = {{0, 1, 1}, {0, 3, 1}, {1, 0, 2}, {1, 4, 2}, {2, 0, 2}, {2, 4, 2}, {2, 1, 1}, {2, 3, 1}};

void init()
{
  memset(map, 0, sizeof(map));
  memset(mapt, 0, sizeof(mapt));
}

bool input()
{
  int i, j;
  char c;
  for (i = 0; i < 5; ++i)
  {
    for (j = 0; j < 10; ++j)
    {
      scanf("%c", &c);
      if (c == '0')
        return false;
      if (c == ' ')
        map[i][j] = 0;
      if (c == '_')
        map[i][j] = 1;
      if (c == '|')
        map[i][j] = 2;
      if (c == '#')
        scanf("%c", &c);
    }
  }
  for (i = 0; i < 5; ++i)
    for (j = 0; j < 9; ++j)
      mapt[0][i][j] = map[i][j];
  return true;
}

void printMap(int t)
{
  int i, j;
  for (i = 0; i < 5; ++i)
  {
    for (j = 0; j < 9; ++j)
      printf("%d", mapt[t][i][j]);
    putchar('\n');
  }
  putchar('\n');
}

void copyMap(int k)
{
  int i, j;
  for (i = 0; i < 5; ++i)
    for (j = 0; j < 9; ++j)
      mapt[k][i][j] = mapt[k - 1][i][j];
}

bool subSquare(int t, int i, int j, int k)
{
  int a, b, inew, jnew;
  int isub = i - spuare[k][0];
  int jsub = j - spuare[k][1];
  // 首先8条边符合
  for (a = 0; a < 8; ++a)
  {
    inew = isub + spuare[a][0];
    jnew = jsub + spuare[a][1];
    if (inew < 0 || inew >= 5 || jnew < 0 || jnew >= 9)
      return false;
      // t == 1时,8条边必须都存在
    if(t == 1 && !mapt[t][inew][jnew]) return false;
    mapt[t][inew][jnew] = 0;
  }
  // 8条边中间不能有内容
  for(i = 1; i < 3; ++i) {
    for(j = 1; j < 4; ++j) {
      inew = isub + i;
      jnew = jsub + j;
      if(mapt[t][inew][jnew]) return false;
    }
  }
  return true;
}

bool clear(int t)
{
  int i, j;
  for (i = 0; i < 5; ++i)
    for (j = 0; j < 9; ++j)
    {
      if (mapt[t][i][j])
        return false;
    }
  return true;
}

bool computed(int t)
{
  // printMap(t);
  if (clear(t))
    return true;
  if (t >= 6)
    return false;
  int i, j, k;
  for (i = 0; i < 5; ++i)
  {
    for (j = 0; j < 9; ++j)
    {
      if (!mapt[t][i][j])
        continue;
      for (k = 0; k < 8; ++k)
      {
        if (spuare[k][2] != mapt[t][i][j])
          continue;
        copyMap(t + 1);
        // printf("%d %d %d %d %d\n", t, i, j, k, subSquare(t + 1, i, j, k));
        if (!subSquare(t + 1, i, j, k))
          continue;
        if (computed(t + 1))
          return true;
      }
    }
  }
  return false;
}

int main()
{
  int i = 0;
  while (1)
  {
    ++i;
    init();
    if (!input())
      break;
    printf("Case %d: ", i);
    if (computed(0))
      printf("Yes\n");
    else
      printf("No\n");
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值