CF31D解题报告
题意
给你一个长 \(W\) 宽 \(H\) 的矩形,其中左下角为 \((0,0)\),右上角为 \((W,H)\)。
之后给你一个 \(n\) 表示切多少刀,每一刀给出起始坐标和结束坐标,不一定从头切到尾。
分析
先说一下,这里可以看作一个个方格连接起来,下面说的坐标是方格的,而每一刀的坐标是边上的,需要转换一下把边转到方格上。可以自行画图理解。
先来看每一刀,针对这个数据范围,可以直接去标记被切的那一列或行附近的方格不能朝这里走。具体的,定义一个三维数组 \(vis1_{i,x,y}\),第一维表示方向,第二、三维表示坐标,如果为 \(1\) 那么 \((x,y)\) 不能走 \(i\) 方向(和方向数组对应)。
接下来核心部分,考虑到要求每一部分的大小,并且与棋盘图上的搜索类似,可以直接当连通块来做,具体不在此赘述。最后排序输出。
注意,一条边会导致两个方向不能走过来,\(vis1\) 要在两个方向进行更新,注意两点坐标差异。
代码
#include <bits/stdc++.h>
using namespace std;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
int w, h, n, cnt, len;
int x1, y1, x2, y2;
int vis[105][105], vis1[4][105][105];
vector<int> v;
void dfs(int x, int y){
cnt++;
vis[x][y] = 1;
for (int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if (nx > 0 && nx <= w && ny > 0 && ny <= h && vis[nx][ny] == 0 && vis1[i][x][y] == 0) dfs(nx, ny);
}
}
int main(){
scanf("%d%d%d", &w, &h, &n);
for (int i = 1; i <= n; i++){
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
if (x1 == x2){//处理行
for (int j = y1 + 1; j <= y2; j++) vis1[1][x1][j] = vis1[3][x1 + 1][j] = 1;//边转方格
}
else{//处理列
for (int j = x1 + 1; j <= x2; j++) vis1[0][j][y1] = vis1[2][j][y1 + 1] = 1;
}
}
for (int i = 1; i <= w; i++){
for (int j = 1; j <= h; j++){
if (vis[i][j] == 0){
cnt = 0;//连通块大小
dfs(i, j);//标记连通块
v.push_back(cnt);
}
}
}
sort(v.begin(), v.end());//排序输出
for (int i = 0; i < v.size(); i++) printf("%d ", v[i]);
return 0;
}