ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 20056] 마법사 상어와 파이어볼
    C 프로그래밍/BOJ 2022. 10. 10. 15:34
    728x90

    https://www.acmicpc.net/problem/20056

     

    20056번: 마법사 상어와 파이어볼

    첫째 줄에 N, M, K가 주어진다. 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다. 서로 다른 두 파이어볼의 위치

    www.acmicpc.net

    #include <cstdio>
    #include <vector>
    #include <cstring>
    int N, M, K;
    struct _ft
    {
    	int idx;	// 벡터의 몇번째 칸에 위치해 있는가
    	int r, c;
    	int m, d, s;
    };
    
    _ft Fire[10000 + 2];
    _ft Tmp[10000 + 2];
    
    std::vector<int> Board[50 + 2][50 + 2];
    
    int Same[4] = { 0, 2, 4, 6 };
    int Diff[4] = { 1, 3, 5, 7 };
    
    
    void debug()
    {
    	for (int i = 1; i <= M; i++) {
    		printf("[%d] %d %d %d %d %d\n", Fire[i].idx, Fire[i].r, Fire[i].c, Fire[i].m, Fire[i].s, Fire[i].d);
    	}
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= N; j++) {
    			if (!Board[i][j].empty()) printf("%d ", Board[i][j].size());
    			else printf("%d ", 0);
    		}
    		printf("\n");
    	}
    }
    
    
    
    void input()
    {
    	scanf("%d %d %d", &N, &M, &K);
    	for (int i = 1; i <= M; i++) {
    		// 서로 다른 두 파이어볼의 위치가 같은 경우는 입력으로 주어지지 않는다
    		// 처음 입력 시 무조건 0번째 벡터에 위치
    		scanf("%d %d %d %d %d", &Fire[i].r, &Fire[i].c, &Fire[i].m, &Fire[i].s, &Fire[i].d);
    	}
    }
    
    
    
    void move()
    {
    	static int dir_x[8] = { -1, -1, 0, 1, 1, 1, 0, -1 };
    	static int dir_y[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
    
    	for (int i = 1; i <= M; i++) {		// M개의 파이어볼을 이동한다. 
    		_ft data = Fire[i];
    	
    		int nr = data.r + (data.s * dir_x[data.d] % N);
    		if (nr < 1) nr += N;
    		else if (nr > N) nr -= N;
    		int nc = data.c + (data.s * dir_y[data.d] % N);
    		if (nc < 1) nc += N;
    		else if (nc > N) nc -= N;
    		Board[nr][nc].push_back(i);
    		Fire[i].idx = Board[nr][nc].size() - 1;
    		Fire[i].r = nr;
    		Fire[i].c = nc;
    	}
    }
    
    
    
    int chk()
    {
    	int num = 1;
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= N; j++) {
    			if (!Board[i][j].empty() && Board[i][j].size() == 1) {	// 임시 구조체에 Fire 모든 내용 옮겨줌
    				Tmp[num] = Fire[Board[i][j][0]];
    				num++;
    				Board[i][j].clear();
    			}
    			if (!Board[i][j].empty() && Board[i][j].size() >= 2) {
    				int tm = 0;	// 총질량
    				int ts = 0;	// 총속력
    				int even = 0;
    				int odd = 0;
    				// 연산 진행
    				int sz = Board[i][j].size();
    				for (int k = 0; k < sz; k++) {
    					tm += Fire[Board[i][j][k]].m;
    					ts += Fire[Board[i][j][k]].s;
    					if (Fire[Board[i][j][k]].d % 2 == 0) odd++;
    					else even++;
    				}
    				Board[i][j].clear();			// 같은 칸에 있는 파이어볼은 모두 하나로 합쳐진다. 
    				if (tm / 5 == 0) continue;
    				for (int k = 0; k <4; k++) {	// 파이어볼은 4개의 파이어볼로 나누어진다. 
    					Tmp[num].idx = k;
    					Tmp[num].r = i;
    					Tmp[num].c = j;
    					Tmp[num].m = tm / 5;
    					Tmp[num].s = ts / sz;
    					if (even == sz || odd == sz) Tmp[num].d = Same[k];
    					else Tmp[num].d = Diff[k];
    					num++;
    				}
    			}
    		}
    	}
    	return num - 1;
    }
    
    
    
    void init_info(int cnt)
    {
    	for (int i = 1; i <= M; i++) {
    		Fire[i] = { 0, 0, 0, 0, 0, 0 };
    	}
    	for (int i = 1; i <= cnt; i++) {
    		Fire[i] = Tmp[i];
    	}
    	M = cnt;
    	for (int i = 1; i <= M; i++) {
    		Tmp[i] = { 0, 0, 0, 0, 0, 0 };
    	}
    }
    
    
    
    void simul()
    {
    	for (int cmd = 0; cmd < K; cmd++) {	// K번 명령한다. 
    		move();
    		int cnt = chk();		// 파이어볼이 합쳐지고 나눠지면서 그 수가 바뀐다.
    		init_info(cnt);			// Tmp 구조체에 있는 파이어볼 정보들 Fire 구조체로 옮겨줄것임
    	}
    }
    
    
    
    int output()
    {
    	int total = 0;
    	for (int i = 1; i <= M; i++) {
    		total += Fire[i].m;
    	}
    	return total;
    }
    
    
    
    int main()
    {
    	input();
    	simul();
    	int ans = output();
    	printf("%d\n", ans);
    	return 0;
    }

    주석... 참고.....

     


    ++ 22.10.27 다시 풀어봄 

    딱히 더 좋은 코드 같지는 않지만, 그리고 처음 풀 때 난 OOB가 같은 이유인지는 잘 기억 안나지만 일단 기록해본다.. 

    #include <cstdio>
    #include <vector>
    #include <list>
    int N, M, K;
    
    struct _st
    {
    	int r, c;
    	int m, s, d;
    
    }FB[10000 + 2];
    _st TB[10000 + 2];	// temp
    
    std::vector<int> V[50 + 2][50 + 2];	// 구조체의 몇번째 파이어볼이 담겼는지
    std::vector<int> C[50 + 2][50 + 2];	// temp
    
    int same_dir[4] = { 0, 2, 4, 6 };
    int diff_dir[4] = { 1, 3, 5, 7 };
    
    void input()
    {
    	scanf("%d %d %d", &N, &M, &K);
    	for (int i = 1; i <= M; i++) {
    		int r = 0, c = 0, m = 0, s = 0, d = 0;
    		scanf("%d %d %d %d %d", &r, &c, &m, &s, &d);
    		FB[i] = { r, c, m, s, d };
    		V[r][c].push_back(i);
    	}
    }
    
    
    void move_ball()
    {
    	// 상 대 우 대 하 대 좌 대
    	static int dir_x[8] = { -1, -1, 0, 1, 1, 1, 0,  -1 };
    	static int dir_y[8] = { 0,  1,  1, 1, 0, -1, -1, -1 };
    
    	for (int i = 1; i <= M; i++) {
    		int x = FB[i].r;
    		int y = FB[i].c;
    		int m = FB[i].m;
    		int d = FB[i].d;
    		int s = FB[i].s;
    
    		int nx = x + dir_x[d] * (s % N);
    		if (nx < 1) nx += N;
    		else if (nx > N) nx -= N;
    		int ny = y + dir_y[d] * (s % N);
    		if (ny < 1) ny += N;
    		else if (ny > N) ny -= N;
    
    		FB[i] = { nx, ny, m, s, d };	// 갱신
    		C[nx][ny].push_back(i);
    	}
    
    	// V init
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= N; j++) {
    			V[i][j].clear();
    		}
    	}
    }
    
    
    void gt_two()
    {
    	int tnum = 1;
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= N; j++) {
    			if (C[i][j].size() >= 2) {
    				int mass = 0;
    				int velo = 0;
    				int cnt = C[i][j].size();
    				int even = 0;
    				int odd = 0;
    				
    				for (int k = 0; k < cnt; k++) {
    					mass += FB[C[i][j][k]].m;
    					velo += FB[C[i][j][k]].s;
    					if (FB[C[i][j][k]].d % 2) odd++;
    					else even++;
    				}
    
    				if (mass / 5 > 0) {
    					for (int b = 0; b < 4; b++) {
    						if (even == cnt || odd == cnt) TB[tnum] = { i, j, mass / 5, velo / cnt, same_dir[b] };
    						else TB[tnum] = { i, j, mass / 5, velo / cnt, diff_dir[b] };
    						V[i][j].push_back(tnum);
    						tnum++;
    					}
    				}
    			}
    			else if (C[i][j].size() > 0) {
    				TB[tnum] = FB[C[i][j][0]];
    				V[i][j].push_back(tnum);
    				tnum++;
    			}
    			C[i][j].clear();
    		}
    	}
    
    	//FB init
    	for (int i = 1; i <= M; i++) {
    		FB[i] = { 0, 0, 0, 0, 0 };
    	}
    
    	M = tnum - 1;
    }
    
    
    
    void mig_info()
    {
    	for (int i = 1; i <= M; i++) {
    		FB[i] = TB[i];
    	}
    
    	// TB init
    	for (int i = 1; i <= M; i++) {
    		TB[i] = { 0, 0, 0, 0, 0 };
    	}
    }
    
    
    
    void simulation()
    {
    	for (int cmd = 0; cmd < K; cmd++) {
    		move_ball();
    		//debug();
    		gt_two();
    		mig_info();
    		//debug_fb();
    	}
    }
    
    int output()
    {
    	int total = 0;
    	for (int i = 1; i <= M; i++) {
    		total += FB[i].m;
    	}
    	return total;
    }
    
    
    int main()
    {
    	input();
    	simulation();
    	int ans = output();
    	printf("%d\n", ans);
    	return 0;
    }

    여기서 중요한 점은 50 * 50 맵에서 각 칸에 파이어볼이 모두 2개 이상 존재하고, 합쳐져서 4개가 새로 만들어졌을 때 이다. 

    따라서 파이어볼을 저장하는 구조체 사이즈를 2500(처음에 50 * 50맵이라서 이렇게 할당함) 이 아니라 50 * 50 * 4 즉 최소 10000을 할당해주어야 한다. 

    728x90

    'C 프로그래밍 > BOJ' 카테고리의 다른 글

    [백준 17779] 게리맨더링 2  (0) 2022.10.10
    [백준 20057] 마법사 상어와 토네이도  (0) 2022.10.10
    [백준 17837] 새로운 게임 2  (0) 2022.10.10
    [백준 19237] 어른 상어  (0) 2022.10.10
    [백준 1726] 로봇  (0) 2022.10.10

    댓글

Designed by Tistory.