11589 - Save the President(暴力+技巧枚举)

链接:11589 - Save the President

题意:有n个爆炸区域,每个区域有一个爆炸时间,现在要保护总统,要保证总统的生存空间为x, y, z;并且不被炸到,问有多少个不同时间空间的位置。
思路:算上时间,算是一个四维坐标系,问题转化为四维坐标系上有一些点,你要找出前三维大小为(x,y,z)的所有位置。
且这个大小内没有点。
这题我直接暴力就过了。。而且时间很快,8层for居然不超时。
然后看了网上一个大神的代码,简直屌,大概是运用了前缀求区间和,然后去判断一个区间的时候就减掉即可。不过这题是四维的,常规方法解决起来容易写乱,学习了大神的方法。链接:https://code.google.com/r/469841185-13a/source/browse/TrainingGuide/exercises/ch1/Efficient/uva11589.cpp?spec=svne76e7c8fa296c14c703a746d1e7dbab8aa115212&r=e76e7c8fa296c14c703a746d1e7dbab8aa115212#37
代码:
暴力过的:
#include <stdio.h>
#include <string.h>

const int N = 2505;
int n, q, h1, m1, h2, m2, time1, time2, vis[20][20][20][105], tim;
struct Point {
	int x, y, z;
	Point() {}
	void scan() {
		scanf("%d%d%d", &x, &y, &z);
	}
} p, s, e, v;

bool judge(int x, int y, int z, int ti) {
	int i, j, k, l;
	for (i = x; i < x + v.x; i++) {
		for (j = y; j < y + v.y; j++) {
			for (k = z; k < z + v.z; k++) {
				for (l = ti; l < ti + tim; l++) {
					if (vis[i][j][k][l]) return false;
				}
			}
		}
	}
	return true;
}

int solve() {
	int ans = 0, i, j, k, t;
	for (i = 0; i <= p.x - v.x; i++) {
		for (j = 0; j <= p.y - v.y; j++) {
			for (k = 0; k <= p.z - v.z; k++) {
				for (t = 0; t <= 96 - tim; t++) {
					if (judge(i, j, k, t)) {
						ans++;
					}
				}
			}
		}
	}
	return ans;
}

int main() {
	int cas = 0;
	while (~scanf("%d%d%d%d%d", &n, &p.x, &p.y, &p.z, &q) && n) {
		memset(vis, 0, sizeof(vis));
		for (int i = 1; i <= n; i++) {
			s.scan(); e.scan();
			scanf("%d:%d%d:%d", &h1, &m1, &h2, &m2);
			time1 = h1 * 4 + m1 / 15;
			time2 = h2 * 4 + m2 / 15;
			for (int x = s.x; x < e.x; x++) {
				for (int y = s.y; y < e.y; y++) {
					for (int z = s.z; z < e.z; z++) {
						for (int t = time1; t < time2; t++) {
							vis[x][y][z][t] = 1;
						}
					}
				}
			}
		}
		printf("3D World %d:\n", ++cas);
		while (q--) {
			v.scan();
			scanf("%d:%d", &h1, &m1);
			tim = h1 * 4 + m1 / 15;
			int ans = solve();
			if (ans)
				printf("%d safe place(s) found\n", ans);
			else
				printf("No safe place(s) found\n");
		}
	}
	return 0;
}

借鉴大神的方法:
#include <stdio.h>
#include <string.h>

const int N = 20;
const int M = 105;

int sum[N][N][N][M], n, dx, dy, dz, q, b0, b1, b2, b3;

void tra(int bit) {
	b0 = bit&1; b1 = (bit>>1)&1; b2 = (bit>>2)&1; b3 = (bit>>3);
}

int coeff() {
	return (b0 + b1 + b2 + b3) % 2 == 1 ? 1 : -1;
}

int solve(int x, int y, int z, int t) {
	int ans = 0;
	for (int i = 1; i <= dx - x + 1; i++)
		for (int j = 1; j <= dy - y + 1; j++)
			for (int k = 1; k <= dz - z + 1; k++)
				for (int l = 1; l <= 96 - t + 1; l++) {
					int s = 0;
					for (int bit = 0; bit < 16; bit++) {
						tra(bit);
						s += sum[i - 1 + b0 * x][j - 1 + b1 * y][k - 1 + b2 * z][l - 1 + b3 * t] * coeff();
					}
					if (!s)
						ans++;
				}
	return ans;
}

int main() {
	int cas = 0;
	while (~scanf("%d%d%d%d%d", &n, &dx, &dy, &dz, &q) && n) {
		memset(sum, 0, sizeof(sum));
		printf("3D World %d:\n", ++cas);
		while (n--) {
			int x1, y1, z1, x2, y2, z2, h1, m1, h2, m2;
			scanf("%d%d%d%d%d%d%d:%d%d:%d", &x1, &y1, &z1, &x2, &y2, &z2, &h1, &m1, &h2, &m2);
			int t1 = h1 * 4 + m1 / 15, t2 = h2 * 4 + m2 / 15;
			for (int i = x1 + 1; i <= x2; i++)
				for (int j = y1 + 1; j <= y2; j++)
					for (int k = z1 + 1; k <= z2; k++)
						for (int l = t1 + 1; l <= t2; l++)
							sum[i][j][k][l] = 1;
		}
		for (int i = 1; i <= dx; i++)
			for (int j = 1; j <= dy; j++)
				for (int k = 1; k <= dz; k++)
					for (int l = 1; l <= 96; l++)
						for (int bit = 1; bit < 16; bit++) {
							tra(bit);
							sum[i][j][k][l] += sum[i - b0][j - b1][k - b2][l - b3] * coeff();
						}
						while (q--) {
							int x, y, z, h, m;
							scanf("%d%d%d%d:%d", &x, &y, &z, &h, &m);
							int t = h * 4 + m / 15;
							int ans = solve(x, y, z, t);
							if (ans) printf("%d safe place(s) found\n", ans);
							else printf("No safe place(s) found\n");
						}
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值