题解:P11372 「CZOI-R2」加训

暴力

三重循环,枚举学生,障碍和老师,再判断是否合法。

时间复杂度:\(\Theta (mxy)\)。但是会 TLE。

暴力优化

用数组 \(oier\) 来存储二元组 \((x, y)\) 对应的坐标 \(z\)

这样就省去的开三维数组的成本。

然后只用枚举学生和老师,再判断维度坐标不同数是否为 \(k-1\) 个,以及中间有没有障碍即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

const int maxm = 1003;
vector<int> oier[maxm][maxm]; // oier: 存储 (x, y) 的坐标 z 
int n, k, m, x, y;
int oi[maxm][5], bar[maxm][5], tea[maxm][5];
// oi: 学生,bar: 障碍,tea: 老师 
int ans[maxm], d[5]; // d: d[1], d[2], d[3] 存储 (x, y, z) 
// ans: 答案 
// check: 判断中间是否有障碍 
bool check() {
	int x = d[1], y = d[2], z = d[3];
	for (int i = 0; i < oier[x][y].size(); i++) {
		if (oier[x][y][i] == z) // 如果 z 坐标相同,说明撞到一起,也就是有障碍 
			return 1;
	}
	return 0;
}

int main() {
	scanf("%d%d%d%d%d", &n, &k, &m, &x, &y);
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= k; j++) 
			scanf("%d", &oi[i][j]);
		oier[oi[i][1]][oi[i][2]].push_back(oi[i][3]);
	}
	for (int i = 1; i <= x; i++) {
		for (int j = 1; j <= k; j++) 
			scanf("%d", &bar[i][j]);
		oier[bar[i][1]][bar[i][2]].push_back(bar[i][3]);
	}
	for (int i = 1; i <= y; i++) {
		for (int j = 1; j <= k; j++) 
			scanf("%d", &tea[i][j]);
		oier[tea[i][1]][tea[i][2]].push_back(tea[i][3]);
	}
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= y; j++) {
			int cha = 0, l = 0;
			// l: 记录不同的那一个维度是在哪一位 
			for (int p = 1; p <= k; p++) { // 判断维度不同数量 
				if (oi[i][p] == tea[j][p])
					cha++;
				else
					l = p;
				d[p] = oi[i][p]; // d 存储学生的坐标 
			}
			if (cha != k - 1) continue;
			int cnt = 1;
			// 因为不存在 2 个坐标相同,所以可以直接比大小,确定从那个开始 
			int start = max(oi[i][l], tea[j][l]);
			int fin = min(oi[i][l], tea[j][l]);
			for (int p = fin + 1; p < start; p++) {
				d[l] = p; // d[l] 是不同的那一个维度,变为 p 就是在循环看这一位是不是障碍 
				if (check()) {
					cnt = 0;
					break;
				}
			}
			ans[j] += cnt; // 答案更新 
		}
	}
	for (int i = 1; i <= y; i++)
		printf("%d ", ans[i]);
	return 0;
}
posted @ 2024-12-15 21:15  Panda_LYL  阅读(17)  评论(0)    收藏  举报