1602 - Lattice Animals

本文详细介绍了如何通过枚举、储存和检验的方式,找到符合特定条件的自由多形块(如五边形或八边形)来填充不同尺寸的矩形。着重于使用C++实现这一过程,包括外函数的使用、坐标系的建立、多形块的旋转和平移等关键步骤。特别关注了多形块的旋转和镜像对称性,以及如何通过这些操作来确保找到的多形块是独特的且适合目标矩形的填充。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lattice animal is a set of connected sites on a lattice. Lattice animals on a square lattice are especially popular subject of study and are also known as polyominoes. Polyomino is usually represented as a set of sidewise connected squares. Polyomino with n squares is called n-polyomino. In this problem you are to find a number of distinct free n-polyominoes that fit into rectangle w×h. Free polyominoes can be rotated and flipped over, so that their rotations and mirror images are considered to be the same. For example, there are 5 different pentominoes (5-polyominoes) that fit into 2×4 rectangle and 3 different octominoes (8-polyominoes) that fit into 3×3 rectangle.

Input

The input file contains several test cases, one per line. This line consists of 3 integer numbers n, w, and h ( 1n10, 1w, hn).
Output

For each one of the test cases, write to the output file a single line with a integer number – the number of distinct free n-polyominoes that fit into rectangle w×h.
Sample Input

5 1 4
5 2 4
5 3 4
5 5 5
8 3 3
Sample Output

0
5
11
12
3

我有话说:
这道题在细节上的处理是比较繁琐的。如果没有网上细致的题解,我觉得完成是很成问题的。
先是基本的思路,依靠set这个强大的工具枚举,储存,检验。把一个个单位格子编上坐标,和常见的坐标轴一样。然后就是从每个已有的格子开始在旁边不断地添上一块。并进行检验。所以难免要枚举所有的情况各种的n,w,h。最后输出。
请先把所有的外函数都先看完,并清楚它们的功能。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;

struct Cell {
  int x, y;
  Cell(int x=0, int y=0):x(x),y(y) {};
  bool operator < (const Cell& rhs) const {
    return x < rhs.x || (x == rhs.x && y < rhs.y);
  }
};

typedef set<Cell> Polyomino;

#define FOR_CELL(c, p) for(Polyomino::const_iterator c = (p).begin(); c != (p).end(); ++c)//定义,否则写写实在太麻烦

inline Polyomino normalize(const Polyomino &p) {//找到最小的x,y
  int minX = p.begin()->x, minY = p.begin()->y;
  FOR_CELL(c, p) {
    minX = min(minX, c->x);
    minY = min(minY, c->y);
  }
  Polyomino p2;    
  FOR_CELL(c, p)
    p2.insert(Cell(c->x - minX, c->y - minY));//以此为坐标轴重新确立坐标,可以看成平移
  return p2;
}

inline Polyomino rotate(const Polyomino &p) {//顺时针旋转
  Polyomino p2;
  FOR_CELL(c, p)
    p2.insert(Cell(c->y, -c->x));
  return normalize(p2);
}

inline Polyomino flip(const Polyomino &p) {//上下做镜面对称变换
  Polyomino p2;
  FOR_CELL(c, p)
    p2.insert(Cell(c->x, -c->y));
  return normalize(p2);
}

const int dx[] = {-1,1,0,0};
const int dy[] = {0,0,-1,1};
const int maxn = 10;

set<Polyomino> poly[maxn+1];//已有的联通块
int ans[maxn+1][maxn+1][maxn+1];

//添加一个联通块,并判断他是不是新的联通块,如果是的话,加入polyonimo集合
void check_polyomino(const Polyomino& p0, const Cell& c) {
  Polyomino p = p0;
  p.insert(c);
  p = normalize(p);

  int n = p.size();
  for(int i = 0; i < 4; i++) {
    if(poly[n].count(p) != 0) return;
    p = rotate(p);
  }                                                                                                                                                                      
  p = flip(p);
  for(int i = 0; i < 4; i++) {
    if(poly[n].count(p) != 0) return;
    p = rotate(p);
  }
  poly[n].insert(p);
}

void generate() {
  Polyomino s;
  s.insert(Cell(0, 0));
  poly[1].insert(s);

  // generate生成
  for(int n = 2; n <= maxn; n++) {
    for(set<Polyomino>::iterator p = poly[n-1].begin(); p != poly[n-1].end(); ++p)
      FOR_CELL(c, *p)
        for(int dir = 0; dir < 4; dir++) {
          Cell newc(c->x + dx[dir], c->y + dy[dir]);
          if(p->count(newc) == 0) check_polyomino(*p, newc);//如果和原来的p中任意一点都不重合的话,至少来看在目前是有效的。不过要进一步检验
        }
  }//枚举

  // precompute answers
  //预计算的答案
  for(int n = 1; n <= maxn; n++)
    for(int w = 1; w <= maxn; w++)
      for(int h = 1; h <= maxn; h++) {
        int cnt = 0;
        for(set<Polyomino>::iterator p = poly[n].begin(); p != poly[n].end(); ++p) {
          int maxX = 0, maxY = 0;
          FOR_CELL(c, *p) {
            maxX = max(maxX, c->x);
            maxY = max(maxY, c->y);
          }
          if(min(maxX, maxY) < min(h, w) && max(maxX, maxY) < max(h, w))//最理想的符合状态
            ++cnt;
        } 
        ans[n][w][h] = cnt;
      }
}

int main() {
  generate();

  int n, w, h;
  while(scanf("%d%d%d", &n, &w, &h) == 3) {
    printf("%d\n", ans[n][w][h]);
  }
  return 0;
}
### Flat-Lattice 的概念 Flat-lattice 是一种用于处理自然语言处理任务的数据结构,特别是在涉及词典信息的任务中表现出色。这种结构能够将复杂的 lattice 展平成更易于处理的形式,同时保留原有的语义关系[^2]。 在具体实现方面,flat-lattice 可以定义为一组跨度(span),其中每个跨度代表一个标记(即字符或单词),并附带头部和尾部索引,用来指示该标记在原序列中的起始和结束位置。对于单个字符而言,其头部和尾部索引相同;而对于多字符组成的词语,则会记录下整个词语范围内的首尾位置。 ### Flat-Lattice 的实现方式 为了更好地理解 flat-lattice 如何运作,下面给出一段 Python 代码作为示例: ```python class Span: def __init__(self, start, end, label): self.start = start self.end = end self.label = label def build_flat_lattice(tokens, dictionary): spans = [] # 构建基于字面意思的初始span列表 for i, token in enumerate(tokens): span = Span(i, i+1, 'char') spans.append(span) # 添加来自词典的新spans for entry in dictionary.entries(): positions = find_sublist_positions(tokens, entry.tokens()) for pos in positions: new_span = Span(pos, pos+len(entry), entry.name) spans.append(new_span) return sorted(spans, key=lambda s: (s.start, -s.end)) ``` 此函数 `build_flat_lattice` 接收两个参数:一个是待分析的文本分词结果 `tokens` ,另一个是从外部加载得到的领域特定术语库 `dictionary` 。通过遍历这些输入数据,程序创建了一系列 Span 对象,并按照它们在原文档中的顺序进行了排序。 ### 应用场景 FLAT 模型利用了上述提到的 flat-lattice 结构,在 Transformer 编码器之上引入了一种新的位置编码机制,使得模型能够在不改变内部架构的情况下融入额外的知识源——比如预先编译好的词汇表。这种方法不仅提高了实体识别任务的表现精度,同时也保证了高效的 GPU 并行运算能力[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值