UVA-11214 守卫棋盘 题解答案代码 算法竞赛入门经典第二版

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

题目不难,我一开始猜测可能要用到一些优化方法,但是还没用到就AC了。

题目里面只说了使用皇后棋占据或者守卫棋盘上的位置,但是没有说明是如何占据和守卫的。这需要了解国际象棋才行,国际象棋中皇后可以沿着横向,纵向,斜向三个方向移动,且移动距离没有限制,在棋盘上像一个米字形。可以网上看一下相关资料就明白了。因此占据指的是棋子位于对应位置,守卫指的是棋子可以移动到这个位置。

这里依然使用的是迭代加深搜索,使用以下剪枝策略:

  1. 已经有棋子的对应行和列就无需遍历了,棋子不会放置在同一行或者列。

  2. range数组表示棋盘棋子可以守卫的区域,值可以叠加多次,这意味着可以多个棋子守卫同一个地方。遍历完恢复数据的时候 -1,减到0表示没有棋子可以守卫这个位置了。

AC代码

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;

int n, m;
// 输入数据,表示需要标记的位置
int marked[12][12];
// 表示已经覆盖的位置 值表示已经覆盖的次数
int range[12][12];
int hasLine[12], hasColumn[12];

vector<int> vec;

bool judge()
{
  int i, j;
  for (i = 0; i < n; ++i)
  {
    for (j = 0; j < m; ++j)
    {
      if (!marked[i][j])
        continue;
      if (!range[i][j])
        return false;
    }
  }
  return true;
}

bool loop(int num, int a, int b)
{
  int i, j, leave, i1, i2;
  if (num == 0)
    return judge();
  if (b >= m)
  {
    a = a + 1;
    b = 0;
  }
  if (a >= n)
    return judge();
  for (i = a; i < n; ++i)
  {
    if (hasLine[i])
      continue;
    for (j = (i == a ? b : 0); j < m; ++j)
    {
      if (hasColumn[j])
        continue;
      leave = (n - i - 1) * m + m - j;
      if (leave < num)
      {
        return false;
      }
      // 在i,j处放置一个皇后
      vec.push_back(i * 100 + j);
      // 处理已经覆盖的位置
      for (i1 = 0; i1 < n; ++i1)
        range[i1][j]++;
      for (i2 = 0; i2 < m; ++i2)
        range[i][i2]++;
      for (i1 = 0; i1 < 10; ++i1)
      {
        if (i + i1 >= n || j + i1 >= m)
          break;
        range[i + i1][j + i1]++;
      }
      for (i1 = 0; i1 < 10; ++i1)
      {
        if (i + i1 >= n || j - i1 < 0)
          break;
        range[i + i1][j - i1]++;
      }
      for (i1 = 0; i1 < 10; ++i1)
      {
        if (i - i1 < 0 || j + i1 >= n)
          break;
        range[i - i1][j + i1]++;
      }
      for (i1 = 0; i1 > -10; --i1)
      {
        if (i + i1 < 0 || j + i1 < 0)
          break;
        range[i + i1][j + i1]++;
      }
      range[i][i2] -= 5;
      hasLine[i] = 1;
      hasColumn[j] = 1;

      if (loop(num - 1, i, j + 1))
        return true;

      // 恢复原状
      vec.pop_back();
      // 处理已经覆盖的位置
      for (i1 = 0; i1 < n; ++i1)
        range[i1][j]--;
      for (i2 = 0; i2 < m; ++i2)
        range[i][i2]--;
      for (i1 = 0; i1 < 10; ++i1)
      {
        if (i + i1 >= n || j + i1 >= m)
          break;
        range[i + i1][j + i1]--;
      }
      for (i1 = 0; i1 < 10; ++i1)
      {
        if (i + i1 >= n || j - i1 < 0)
          break;
        range[i + i1][j - i1]--;
      }
      for (i1 = 0; i1 < 10; ++i1)
      {
        if (i - i1 < 0 || j + i1 >= n)
          break;
        range[i - i1][j + i1]--;
      }
      for (i1 = 0; i1 > -10; --i1)
      {
        if (i + i1 < 0 || j + i1 < 0)
          break;
        range[i + i1][j + i1]--;
      }
      range[i][i2] += 5;
      hasLine[i] = 0;
      hasColumn[j] = 0;
    }
  }
  return false;
}

int main()
{
  int i, j, num = 0;
  char c;
  while (scanf("%d %d", &n, &m) == 2)
  {
    if (n == 0 || m == 0)
      return 0;
    getchar();

    memset(marked, 0, sizeof(marked));
    memset(range, 0, sizeof(range));
    memset(hasLine, 0, sizeof(hasLine));
    memset(hasColumn, 0, sizeof(hasColumn));

    for (i = 0; i < n; ++i)
    {
      for (j = 0; j < m; ++j)
      {
        scanf("%c", &c);
        if (c == 'X')
          marked[i][j] = 1;
        else
          marked[i][j] = 0;
      }
      getchar();
    }

    for (i = 0; i < 10; ++i)
    {
      if (loop(i, 0, 0))
        break;
    }
    printf("Case %d: %d\n", ++num, i);
  }

  return 0;
}
相关推荐
临溟夜空的繁星几秒前
C++ STL-- vector
开发语言·c++
哈哈很哈哈10 分钟前
逻辑回归Logistic Regression
算法·机器学习·逻辑回归
甄心爱学习15 分钟前
【极大似然估计/最大化后验】为什么逻辑回归要使用交叉熵损失函数
算法·机器学习·逻辑回归
郝学胜-神的一滴29 分钟前
深度学习入门全解析:从核心概念到实战基础 | 技术研讨会精华总结
人工智能·python·深度学习·算法·cnn
一方热衷.35 分钟前
YOLO26-OBB ONNXruntime部署 python/C++
开发语言·c++·python
梯度下降中39 分钟前
CNN原理精讲
人工智能·算法·机器学习
Qt程序员40 分钟前
基于 C++ 实现自定义字符串 string 类
linux·c++·容器·指针·内存管理·运算符重载
Ivanqhz42 分钟前
活跃范围重写(Live Range Rewriting)
开发语言·c++·后端·算法·rust
xiaoye-duck1 小时前
《算法题讲解指南:优选算法-链表》--51.两数相加,52.两两交换链表中的节点
数据结构·算法·链表
Cosolar1 小时前
阿里CoPaw进阶使用手册:从新手到高手的完整指南
人工智能·后端·算法