Elegant Diamond 题解
中文题面
题目描述
国王雇佣你为他制作一个优雅的菱形。优雅的菱形是由数字组成的二维图形,关于水平轴和垂直轴对称。例如,以下四个图形是优雅的菱形:
2 8 3 7
3 3 8 8 2 2
4 1 4 8 3
3 3
2
下面这三个图形是菱形,但不是优雅的:
2 1 3
1 1 1 2 1 1
1 1 1 1 3 1 3
2 1 1 1
1 2
下面这三个图形不是菱形:
1 2 8 8
1 1 222 0
2 00000
国王会先给你一个菱形,这个菱形可能不是优雅的。你的任务是通过扩展它、添加数字,使其变成优雅的菱形。由于你不想花太多钱,你希望以尽可能小的代价完成这项工作。
定义
大小为 kkk 的菱形由 2k−12k-12k−1 行数字(0-9)组成,数字之间用单个空格分隔,排列方式如下:
- 第 iii 行(1≤i≤k1 \leq i \leq k1≤i≤k)前有 k−ik-ik−i 个空格,接着是 iii 个数字,数字之间用单个空格分隔。
- 第 iii 行(k<i<2kk < i < 2kk<i<2k)前有 i−ki-ki−k 个空格,接着是 2k−i2k-i2k−i 个数字,数字之间用单个空格分隔。
大小为 kkk 的优雅菱形是满足以下两个对称性质的菱形:
- 水平对称:设第 iii 行有 cic_ici 个数字,第 iii 行第 jjj 个数字(j=1j=1j=1 表示第一个数字)必须等于第 ci+1−jc_i+1-jci+1−j 个数字。
- 垂直对称:第 iii 行第 jjj 个数字(i=1i=1i=1 表示第一行)必须等于第 2k−i2k-i2k−i 行第 jjj 个数字。
可以通过添加数字来扩展一个大小为 kkk 的菱形。扩展后的菱形需满足以下条件:
- 扩展结果是一个大小 ≥k\geq k≥k 的菱形。
- 原始菱形是扩展结果的一部分。也就是说,存在某个 XXX 和某个 YYY,使得对于原始菱形中所有第 iii 行第 jjj 个为数字(非空格)的字符,扩展结果中第 i+Yi+Yi+Y 行第 j+Xj+Xj+X 个字符也是数字,且与原始菱形对应位置的数字相同。
扩展菱形的代价等于扩展后菱形中的数字总数减去原始菱形中的数字总数。
输入格式
第一行输入测试用例数 TTT。接下来有 TTT 组测试数据。每组测试数据第一行为一个整数 kkk,接下来为一个大小为 kkk 的菱形。
输出格式
对于每组测试数据,输出一行,格式为 “Case #xxx: yyy”,其中 xxx 为测试编号(从 1 开始),yyy 为将给定菱形扩展为优雅菱形所需的最小代价。如果菱形已经是优雅的,则 y=0y=0y=0。
输入输出样例 #1
输入 #1
4
1
0
2
1
2 2
1
2
1
1 2
1
3
1
6 3
9 5 5
6 3
1
输出 #1
Case #1: 0
Case #2: 0
Case #3: 5
Case #4: 7
说明/提示
样例解释
共有四组数据。前两组数据本身就是大小为 1 和 2 的优雅菱形,无需扩展,代价为 0。第三组可以扩展为如下优雅菱形:
3
1 1
1 2 1
1 1
3
有多种扩展方式,但这是代价最小的一种,代价为 5。第四组可以扩展为如下优雅菱形:
9
1 1
6 3 6
9 5 5 9
6 3 6
1 1
9
……代价为 7。
数据范围
- 1≤T≤1001 \leq T \leq 1001≤T≤100。
小数据范围(4 分,测试点 1 - 可见)
- 时间限制:3 秒。
- 1≤k≤101 \leq k \leq 101≤k≤10。
大数据范围(8 分,测试点 2 - 隐藏)
- 时间限制:6 秒。
- 1≤k≤511 \leq k \leq 511≤k≤51。
解法
思路分析
由题,优雅菱形需要同时满足水平对称和垂直对称,所以可得这个菱形必须关于某个中心点完全对称。
显然,对于任意一个优雅菱形,一定存在一个中心点 (i,j)(i, j)(i,j),能够使得菱形内任意一点 (x,y)(x, y)(x,y),满足 (x,y)(x, y)(x,y) 关于中心点 (i,j)(i, j)(i,j) 的对称点 (2i−x,2j−y)(2i-x, 2j-y)(2i−x,2j−y) 的数字与 (x,y)(x, y)(x,y) 相同。
因为这道题的数据范围很小,所以我们可以考虑通过枚举来实现这道题。我们只需要枚举整个菱形的所有可能对称中心,然后计算其水平对称位置 (x,2j−y)(x, 2j-y)(x,2j−y) 和垂直对称位置 (2i−x,y)(2i-x, y)(2i−x,y),接着判断其对称位置是否符合条件,如果完全对称则标记为可行中心。对于所有的可行中心,我们只需要找到偏移量最小的那一个就可以了。
那么该如何计算呢?对于每个可行中心 (i,j)(i, j)(i,j):
- 偏移量是 dx=∣i−(k−1)∣, dy=∣j−(k−1)∣dx = |i - (k-1)|,\ dy = |j - (k-1)|dx=∣i−(k−1)∣, dy=∣j−(k−1)∣
- 扩展后大小是 k′=k+dx+dyk' = k + dx + dyk′=k+dx+dy
- 需要添加的数字数是 m=(k′)2−k2m = (k')^2 - k^2m=(k′)2−k2(菱形数字总数 =k2= k^2=k2)
然后输出所有可行中心中添加的数字数的最小值就行了。
参考代码
#include <bits/stdc++.h>
#define int long long
#define fast_running ios::sync_with_stdio(false), cin.tie(nullptr)
using namespace std;
int k, n;
string s[200];
signed main() {
fast_running;
int T;
cin >> T;
for (int Case = 1; Case <= T; Case++) {
cin >> k;
n = k * 2 - 1;
cin.ignore(); // 忽略换行符,防止 getline 去世
for (int i = 0; i < n; i++) {
getline(cin, s[i]);
if (s[i].length() < n) s[i] += string(n - s[i].length(), ' ');
// 统一字符长度,方便枚举,防 RE
}
cout << "Case #" << Case << ": ";
int m = INT_MAX;
for (int i = 0; i < n; i++) { // 枚举所有可能得对称中心
for (int j = 0; j < n; j++) {
bool flag = true;
for (int x = 0; x < n && flag; x++) { // 检查可行性
for (int y = 0; y < n && flag; y++) {
if (s[x][y] != ' ') {
int nx = 2 * i - x;
int ny = 2 * j - y;
if (0 <= nx && nx < n) { // 检查垂直对称
if (s[nx][y] != ' ' && s[nx][y] != s[x][y]) flag = false;
}
if (0 <= ny && ny < n) { // 检查水平对称
if (s[x][ny] != ' ' && s[x][ny] != s[x][y]) flag = false;
}
}
}
}
// 如果 (i, j) 是可行中心,计算偏移量
if (flag) m = min(m, abs(i - k + 1) + abs(j - k + 1));
}
}
cout << (k + m) * (k + m) - k * k << '\n';
}
return 0;
}

浙公网安备 33010602011771号