• [洛谷P3693]琪露诺的冰雪小屋


    题目大意:琪露诺的冰雪小屋,我做的第一道大模拟题。

    题解:模拟。。。

    卡点:无数小错误,要是没有写一点调一点,那大概是永远调不出来了。。。

    C++ Code:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <cstdlib>
    #define PutRe(x) {puts(x); return ;}
    inline int min(int a, int b) {return a < b ? a : b;}
    inline int max(int a, int b) {return a > b ? a : b;}
    namespace snow_house {
    	#define MAXN 17
    	#define MAXH 21
    	const int __X[8] = {-1, -1, 0, 1, 1, 1, 0, -1},
    			  __Y[8] = {0, -1, -1, -1, 0, 1, 1, 1}; 
    	//0.上 1.左上 2.左 3.左下 4.下 5.右下 6.右 7.右上 
    	/*
    	x-1,y-1	x-1,y	x-1,y+1
    	x,y-1	x,y		x,y+1
    	x+1,y-1	x+1,y	x+1,y+1
    	*/ 
    	
    	int n, HM, m, Tim;
    	int HR, HC, HX, HY, Height; //左上角位置,长度,宽度,房顶高度 
    	
    	int Ice_Block_Num; //剩余方块数 
    	
    	int Frozen_Value[MAXN][MAXN]; //地面冷冻值 
    	bool Block[MAXN][MAXN][MAXH]; //是否有方块 
    	
    	inline bool over_range(int x, int y) {return x < 0 || y < 0 || x >= n || y >= n;}
    	inline bool over_range(int x, int y, int z) {return over_range(x, y) || z < 0 || z > HM;}
    	
    	void ice_barrage(int R, int C, int D, int S) { //发射冰雪弹幕 
    		int k = 0;
    		for (int i = 0; i <= S; i++) {
    			if (Block[R][C][0]) break;
    			if (Frozen_Value[R][C] < 4) Frozen_Value[R][C]++, k++;
    			R += __X[D], C += __Y[D];
    			if (over_range(R, C)) break;
    		}
    		printf("CIRNO FREEZED %d BLOCK(S)", k);
    		if (Tim != m) puts("");
    	}
    	
    	
    	void make_ice_block() { //造冰砖 
    		int cnt = 0;
    		for (int i = 0; i < n; i++) {
    			for (int j = 0; j < n; j++) if (Frozen_Value[i][j] == 4) {
    				Frozen_Value[i][j] = 0;
    				cnt++;
    			}
    		}
    		Ice_Block_Num += cnt;
    		printf("CIRNO MADE %d ICE BLOCK(S),NOW SHE HAS %d ICE BLOCK(S)
    ", cnt, Ice_Block_Num);
    	}
    	
    	
    	const int Space_X[6] = {1, -1, 0, 0, 0, 0},
    			  Space_Y[6] = {0, 0, 1, -1, 0, 0},
    			  Space_Z[6] = {0, 0, 0, 0, 1, -1};
    	
    	bool can_put(int R, int C, int H) { //是否可以放冰砖(即六个方向有冰砖且此位置没有冰砖) 
    		if (Block[R][C][H]) return false;
    		if (H == 0) return true;
    		for (int i = 0; i < 6; i++) {
    			int x = R + Space_X[i], y = C + Space_Y[i], z = H + Space_Z[i];
    			if (over_range(x, y, z)) continue;
    			if (Block[x][y][z]) return true;
    		}
    		return false;
    	}
    	
    	
    	inline bool outside(int R, int C) {return R < HR || R >= HR + HX || C < HC || C >= HC + HY;}
    	inline bool inside(int R, int C) {return HR + 1 <= R && R <= HR + HX - 2 && HC + 1 <= C && C <= HC + HY - 2;}
    	
    	void put_ice_block(int R, int C, int H) { //放冰砖 
    		if (!Ice_Block_Num) PutRe("CIRNO HAS NO ICE_BLOCK")
    		if (!can_put(R, C, H)) PutRe("BAKA CIRNO,CAN'T PUT HERE")
    		Block[R][C][H] = true; Ice_Block_Num--;
    		if (H == 0) Frozen_Value[R][C] = 0;
    		
    		if (outside(R, C)) PutRe("CIRNO MISSED THE PLACE")
    		if (inside(R, C)) PutRe("CIRNO PUT AN ICE_BLOCK INSIDE THE HOUSE")
    		printf("CIRNO SUCCESSFULLY PUT AN ICE_BLOCK,NOW SHE HAS %d ICE_BLOCK(S)
    ", Ice_Block_Num);
    	}
    	
    	
    	struct point {
    		int x, y, z;
    		inline point(int __x = 0, int __y = 0, int __z = 0) {x = __x, y = __y, z = __z;}
    	};
    	
    	bool vis[MAXN][MAXN][MAXH];
    	
    	int fall_block(int R, int C, int H) { //计算会掉下来多少个冰砖 
    		if (over_range(R, C, H) || !Block[R][C][H]) return 0;
    		memset(vis, false, sizeof vis);
    		std::queue<point> q; while (!q.empty()) q.pop();
    		bool Fallen = true; //判断这个连通块是否有冰砖接地(即是否会掉下) 
    		int cnt = 0;
    		
    		q.push(point(R, C, H)); vis[R][C][H] = true;
    		while (!q.empty()) {
    			point u = q.front(); q.pop();
    			if (u.z == 0) {
    				Fallen = false;
    				break;
    			}
    			for (int i = 0; i < 6; i++) {
    				int x = u.x + Space_X[i], y = u.y + Space_Y[i], z = u.z + Space_Z[i];
    				if (over_range(x, y, z) || vis[x][y][z] || !Block[x][y][z]) continue;
    				vis[x][y][z] = true;
    				q.push(point(x, y, z));
    			}
    		}
    		if (Fallen) {
    			for (int i = 0; i < n; i++) {
    				for (int j = 0; j < n; j++) {
    					for (int k = 0; k < HM; k++) if (vis[i][j][k]) {
    						Block[i][j][k] = false;
    						cnt++;
    					}
    				}
    			}
    		}
    		return cnt;
    	}
    	
    	void remove_ice_block(int R, int C, int H, bool echo = true) { //移除冰砖,echo:是否输出(若为false即为造屋顶阶段,掉落的方块会被回收) 
    		if (!Block[R][C][H]) {
    			if (echo) PutRe("BAKA CIRNO,THERE IS NO ICE_BLOCK")
    			return ;
    		}
    		Block[R][C][H] = false; Ice_Block_Num++;
    		int k = 0; 
    		for (int i = 0; i < 6; i++) k += fall_block(R + Space_X[i], C + Space_Y[i], H + Space_Z[i]);
    		if (!echo) Ice_Block_Num += k;
    		
    		if (echo) {
    			if (!k) puts("CIRNO REMOVED AN ICE_BLOCK");
    			else printf("CIRNO REMOVED AN ICE_BLOCK,AND %d BLOCK(S) ARE BROKEN
    ", k);
    		}
    	}
    	
    	
    	int get_max_height(int x, int y) { //求出该点最高的方块高度 
    		int res = -1;
    		for (int i = 0; i < HM; i++) if (Block[x][y][i]) res = i;
    		return res;
    	}
    	
    	int get_roof_height() { //求屋顶的高度 
    		int res = -1;
    		for (int i = 0; i < HX; i++) {
    			res = max(res, get_max_height(HR + i, HC));
    			res = max(res, get_max_height(HR + i, HC + HY - 1));
    		}
    		for (int i = 1; i < HY - 1; i++) {
    			res = max(res, get_max_height(HR, HC + i));
    			res = max(res, get_max_height(HR + HX - 1, HC + i));
    		}
    		return res + 1;
    	}
    	
    	int calc_block_num(int X_1, int Y_1, int X_2, int Y_2, int H) { //计算高度为H的平面中给定区间的方块数 
    		int res = 0;
    		for (int i = X_1; i <= X_2; i++) {
    			for (int j = Y_1; j <= Y_2; j++) {
    				res += Block[i][j][H]; 
    			}
    		}
    		return res;
    	}
    	
    	inline bool outside(int x, int y, int z) {return outside(x, y) || z > Height;}
    	inline bool inside(int x, int y, int z) {return inside(x, y) && z < Height;}
    	
    	int Inside_Block_Num, Outside_Block_Num; 
    	void calc_rest_of_block_num() { //计算屋内和屋外的方块数
    		for (int i = 0; i < n; i++) {
    			for (int j = 0; j < n; j++) {
    				for (int k = 0; k <= HM; k++) if (Block[i][j][k]) {
    					Inside_Block_Num += inside(i, j, k);
    					Outside_Block_Num += outside(i, j, k); 
    				}
    			}
    		}
    		printf("%d ICE_BLOCK(S) INSIDE THE HOUSE NEED TO BE REMOVED
    ", Inside_Block_Num);
    		printf("%d ICE_BLOCK(S) OUTSIDE THE HOUSE NEED TO BE REMOVED
    ", Outside_Block_Num);
    	} 
    	
    	inline bool is_a_part_of_house(int x, int y, int z) {return !inside(x, y, z) && !outside(x, y, z);}
    	
    	void remove_rest_of_block() { //把多余的方块移除 
    		for (int i = 0; i < n; i++) {
    			for (int j = 0; j < n; j++) {
    				for (int k = 0; k < HM; k++) if (!is_a_part_of_house(i, j, k)) remove_ice_block(i, j, k, false);
    			}
    		}
    	}
    	
    	int Door_X, Door_Y, Door_Max_Value = -1;
    	
    	int mid(int x, int y) { //判断门是否在墙的中间 
    		if (x == HR || x == HR + HX - 1) {
    			if (HY & 1) return y == HC + (HY >> 1);
    			else return (y == HC + (HY >> 1)) || (y == HC + (HY - 1 >> 1));
    		}
    		if (y == HC || y == HC + HY - 1) {
    			if (HX & 1) return x == HR + (HX >> 1);
    			else return (x == HR + (HX >> 1)) || (x == HR + (HX - 1 >> 1));
    		}
    		//出错
    		exit(20040826); 
    		return -1;
    	}
    	
    	int get_block_num(int x, int y) { //求出(x,y)从地面开始的两格有几个方块 
    		return Block[x][y][0] + Block[x][y][1];
    	}
    	
    	int need_block_num(int x, int y) { //求出(x,y)从地面开始的两格还需要几个方块 
    		return !Block[x][y][0] + !Block[x][y][1];
    	}
    	
    	int beside_corner(int x, int y) { //如果门在墙角旁边,就要多放方块修墙角(即可以看见),求出原有几个方块 
    		int res = 0;
    		bool Is_Beside_Corner = false;
    		if (x - 1 == HR) res += get_block_num(x - 1, y), Is_Beside_Corner = true;
    		if (x + 1 == HR + HX - 1) res += get_block_num(x + 1, y), Is_Beside_Corner = true;
    		if (y - 1 == HC) res += get_block_num(x, y - 1), Is_Beside_Corner = true;
    		if (y + 1 == HC + HY - 1) res += get_block_num(x, y + 1), Is_Beside_Corner = true;
    		if (!Is_Beside_Corner) res = 4;
    		return res;
    	}
    	
    	int door_value(int x, int y) { //求出在此建门的优先级 
    		//BBmccc
    		return need_block_num(x, y) << 4 | mid(x, y) << 3 | beside_corner(x, y);
    	}
    	
    	void get_max(int x, int y) { //更新门的位置 
    		int Value = door_value(x, y);
    		if (Value > Door_Max_Value) Door_X = x, Door_Y = y, Door_Max_Value = Value;
    	}
    	
    	void find_door() { //找到建门的最好地点 
    		for (int i = HR + 1; i < HR + HX - 1; i++) {
    			get_max(i, HC);
    			get_max(i, HC + HY - 1);
    		}
    		for (int i = HC + 1; i < HC + HY - 1; i++) {
    			get_max(HR, i);
    			get_max(HR + HX - 1, i);
    		}
    	}
    	
    	#define fix(x, y, z) cnt += !Block[x][y][z], Block[x][y][z] = true
    	#define fix_double(x, y) cnt += need_block_num(x, y), Block[x][y][0] = Block[x][y][1] = true
    	
    	bool is_door(int x, int y, int z) { //判断这个位置是否是门 
    		return x == Door_X && y == Door_Y && z < 2;
    	}
    	
    	int fix_wall() { //修墙,并求出需要的方块数 
    		int cnt = 0;
    		for (int i = HR + 1; i < HR + HX - 1; i++) {
    			for (int j = 0; j < Height; j++) {
    				if (!is_door(i, HC, j)) fix(i, HC, j);
    				if (!is_door(i, HC + HY - 1, j)) fix(i, HC + HY - 1, j);
    			}
    		}
    		for (int i = HC + 1; i < HC + HY - 1; i++) {
    			for (int j = 0; j < Height; j++) {
    				if (!is_door(HR, i, j)) fix(HR, i, j);
    				if (!is_door(HR + HX - 1, i, j)) fix(HR + HX - 1, i, j);
    			}
    		}
    		if (Door_X - 1 == HR) fix_double(Door_X - 1, Door_Y);
    		if (Door_X + 1 == HR + HX - 1) fix_double(Door_X + 1, Door_Y);
    		if (Door_Y - 1 == HC) fix_double(Door_X, Door_Y - 1);
    		if (Door_Y + 1 == HC + HY - 1) fix_double(Door_X, Door_Y + 1);
    		return cnt;
    	}
    	
    	int fix_corner() { //修墙角,并求出需要的方块数 
    		int cnt = 0;
    		for (int i = 0; i < Height; i++) {
    			fix(HR, HC, i);
    			fix(HR, HC + HY - 1, i);
    			fix(HR + HX - 1, HC, i);
    			fix(HR + HX - 1, HC + HY - 1, i);
    		}
    		return cnt;
    	}
    	
    	void make_roof() { //造屋顶 
    		Height = get_roof_height();
    		int Make_Roof_Need = HX * HY - calc_block_num(HR, HC, HR + HX - 1, HC + HY - 1, Height);
    		
    		if (Ice_Block_Num < Make_Roof_Need) PutRe("SORRY CIRNO,NOT ENOUGH ICE_BLOCK(S) TO MAKE ROOF")
    		if (Height < 2 || HX <= 2 || HY <= 2) PutRe("SORRY CIRNO,HOUSE IS TOO SMALL");
    		
    		Ice_Block_Num -= Make_Roof_Need; 
    		for (int i = HR; i < HR + HX; i++) {
    			for (int j = HC; j < HC + HY; j++) Block[i][j][Height] = true;
    		}
    		
    		calc_rest_of_block_num();
    		remove_rest_of_block();
    		if (!Block[HR][HC][Height]) PutRe("SORRY CIRNO,HOUSE IS BROKEN WHEN REMOVING BLOCKS")
    		
    		find_door();
    		
    		int Fix_Wall_Need = fix_wall();
    		if (Ice_Block_Num < Fix_Wall_Need) PutRe("SORRY CIRNO,NOT ENOUGH ICE_BLOCKS TO FIX THE WALL")
    		Ice_Block_Num -= Fix_Wall_Need;
    		puts("GOOD JOB CIRNO,SUCCESSFULLY BUILT THE HOUSE");
    		
    		if (Door_Max_Value >> 4 == 2) puts("DOOR IS OK");
    		else {
    			puts("HOUSE HAS NO DOOR");
    			Ice_Block_Num += Block[Door_X][Door_Y][0] + Block[Door_X][Door_Y][1];
    			Block[Door_X][Door_Y][0] = Block[Door_X][Door_Y][1] = false;
    		}
    		
    		if (!Fix_Wall_Need) puts("WALL IS OK");
    		else puts("WALL NEED TO BE FIXED");
    		
    		int Fix_Corner_Need = fix_corner();
    		if (Ice_Block_Num < Fix_Corner_Need) Ice_Block_Num = 0;
    		else Ice_Block_Num -= Fix_Corner_Need;
    		if (!Fix_Corner_Need) puts("CORNER IS OK");
    		else puts("CORNER NEED TO BE FIXED");
    		
    		printf("CIRNO FINALLY HAS %d ICE_BLOCK(S)
    ", Ice_Block_Num); 
    		
    		if (!Inside_Block_Num && !Outside_Block_Num
    			&& !Fix_Wall_Need && !Fix_Corner_Need
    			&& (Door_Max_Value & 1 << 3) && (Door_Max_Value >> 4 == 2))
    			puts("CIRNO IS PERFECT!");
    		
    	}
    	
    	void start() {
    		scanf("%d", &n);
    		scanf("%d", &HM);
    		scanf("%d%d%d%d", &HR, &HC, &HX, &HY); 
    		scanf("%d", &m);
    		
    		char op[20];
    		for (Tim = 1; Tim <= m; Tim++) {
    			scanf("%s", op);
    			if (strcmp(op, "ICE_BARRAGE") == 0) {
    				int R, C, D, S;
    				scanf("%d%d%d%d", &R, &C, &D, &S);
    				ice_barrage(R, C, D, S);
    				continue;
    			}
    			if (strcmp(op, "MAKE_ICE_BLOCK") == 0) {
    				make_ice_block();
    				continue;
    			}
    			if (strcmp(op, "PUT_ICE_BLOCK") == 0) {
    				int R, C, H;
    				scanf("%d%d%d", &R, &C, &H);
    				put_ice_block(R, C, H);
    				continue;
    			}
    			if (strcmp(op, "REMOVE_ICE_BLOCK") == 0) {
    				int R, C, H;
    				scanf("%d%d%d", &R, &C, &H);
    				remove_ice_block(R, C, H);
    			}
    			if (strcmp(op, "MAKE_ROOF") == 0) {
    				make_roof();
    			}
    		}
    	}
    }
    int main() {
    	snow_house::start();
    	return 0;
    } 
    

      

  • 相关阅读:
    android listview 圆角的实现方案,模仿Iphone的UITableView
    在android编程中插入背景图片
    iOS开发UI篇—UIPickerView控件简单介绍
    iOS开发UI篇章 15-项目中的常见文件
    iOS开发UI篇章之通知中心(NSNotificationCenter)
    iOS开发UI篇章之应用管理的九宫格坐标计算
    iOS开发UI篇章之-Button基础
    Xcode-Run和快捷键
    Css基础-介绍及语法
    CSDN首页> 移动开发 直接拿来用!最火的Android开源项目(完结篇)
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9820855.html
Copyright © 2020-2023  润新知