본문 바로가기

백준/삼성기출

마법사 상어와 파이어볼 / 시뮬레이션

728x90

www.acmicpc.net/problem/20056

 

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

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

www.acmicpc.net

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

using namespace std;


int n, t, k;


//0,1,

int dx[] = {-1,-1,0,1,1,1,0,-1};
int dy[] = {0,1,1,1,0,-1,-1,-1};

struct info {

	int r;
	int c;
	int m;
	int d;
	int s;


};

info nothing = { 0,0,0,0,0 };


void print(vector<info>&infoList) {  //test


	for (int i = 0; i < infoList.size(); i++) {
	
		cout << infoList[i].r << " " << infoList[i].c << " " <<"m:"<< infoList[i].m <<" "<<"d:"<<infoList[i].d<< " "<<"s:"<<infoList[i].s<<endl;;
			
	
	}

}


void move(vector<info>&infoList) {


	vector<info>arr[51][51]; // 2차원 배열에 여러 요소를 넣을 때 이러한 자료구조를 쓴다. 


	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			arr[i][j].clear();   
		}
	}

	int nr, nc;
	for (int i = 0; i < infoList.size(); i++) {
		
		info ifo = infoList[i];

		nr = ifo.r;
		nc = ifo.c;

		arr[nr][nc].push_back(ifo);  // 이동할 위치를 정했으면 arr에 집어 넣어준다. 
	
	}



	infoList.clear();
	
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {

		
			if (arr[i][j].size() == 1) {  // i, j 위치에 한개가 있을 때
				
				infoList.push_back(arr[i][j].front());   
				continue;
			
			}
			else if (arr[i][j].size()  > 1) { //i,j 위치에 1개보다 더 많을 때
				
				int m = 0;
				int s = 0;

				for (int l = 0; l < arr[i][j].size(); l++){

					m += arr[i][j][l].m;   // (i,j) 위치에 질량들을 모두 더한다
					s += arr[i][j][l].s;   // (i,j) 위치에 속도들을 모두 더한다. 

				}


				m /= 5;  // 질량 모두 더하고 5로 나눈다.
				s /= (arr[i][j].size()); // 속력 모두 더하고 해당 위치에 있는 크기만큼 나눈다. 


				if (m == 0) { continue; }
				
				vector<info>dir = arr[i][j];
			
				bool toggle = false;
				
				int idx = 0;
				while (idx<dir.size() && ((dir[idx].d % 2)==0)) { // (i,j) 위치의 모든 방향이 2로 나누어떨어지는지확인
				
					idx++;

				}

				if (idx == dir.size()) { toggle = true; }

				idx = 0;

				while (idx<dir.size() && ((dir[idx].d % 2) != 0)) { // (i,j) 위치의 모든 방향이 2로 안 나누어떨어지는지확인

					idx++;

				}

				if (idx == dir.size()) { toggle = true; }

				int d = 0;

				if (toggle == false) {  // 모두 2로 나누어 떨어지거나 모두 2로 안나누어 떨어지거나 할때 
				
					for (int p = 0; p< 4; p++) {
						
						d = 1 + p * 2;
						infoList.push_back({i,j,m,d,s});
					
					}
				}
				else {  // 그 외
					
					for (int p = 0; p < 4; p++) {

						d = p * 2;
						infoList.push_back({ i, j, m, d, s });

					}
				}
				
			
			}
		}
	}


}

bool cango(int x, int y) {

	return x >= 0 && x < n && y >= 0 && y < n;
}

void simulate(vector<info>&infoList) {
	


	for (int i = 0; i < infoList.size(); i++) {
		
		info ifo = infoList[i];
		
		int r = ifo.r;
		int c = ifo.c;
		int m = ifo.m;
		int d = ifo.d;
		int s = ifo.s;

		int nr, nc;

		nr = (r + dx[d]*s)%n; // 1행은 n-1행과
		nc = (c + dy[d]*s)%n; // 1열은 n-1열과 연결이 되어 있으므로 %를 한다. 

		if (cango(nr, nc)){
			infoList[i] = { nr,nc,m,d,s };
		}
		else {

			if (nr < 0) {
			
				nr = nr + n;  // -1 행이면 3행이 되도록
			
			}
		    if (nc < 0) {
				nc += n; // -1 열이면 3열이 되도록 
			}

			infoList[i] = { nr,nc,m,d,s }; // 이동한 좌표와 정보를 리스트에 저장
		}
	

	}

	move(infoList); //움직이기 시작한다. 

}



int main() {
	


	cin >> n; //격자수
	cin >> t; //파이어볼개수
	cin >> k; //명령수




	int r;
	int c;
	int m;
	int d;
	int s;


	vector<info>infoList;


	for (int i = 0; i < t; i++) {
		
		cin>> r;  //x
		cin>> c;  //y	
		cin>> m;  //질량
		cin>> s;  //속력
		cin>> d;  //방향

		infoList.push_back({ r-1,c-1,m,d,s });
		
	}

	for (int i = 0; i < k; i++) {
		simulate(infoList);
	}

	int totalweight = 0;

	for (int i = 0; i < infoList.size(); i++) {
	
		totalweight += infoList[i].m;
	}

	cout << totalweight << endl;


}

 

<Java>

 

package Samsung;

import java.io.*;
import java.util.*;

public class 마법사상어와파이어볼 {

	static int dx[] = {-1,-1,0,1,1,1,0,-1};
	static int dy[] = {0,1,1,1,0,-1,-1,-1};
	
	static int n,m,k;
	static ArrayList<Ball>[][] map;
	static StringTokenizer st;
	
	public static class Ball{
		
		int r,c,m,d,s;

		public Ball(int r, int c, int m, int s, int d) {
			super();
			this.r = r;
			this.c = c;
			this.m = m;
			this.d = d;
			this.s = s;
		}
		
		
	}
	
	public static boolean cango(int x , int y) {
		
		return x>=1 && x<=n && y>=1 && y<=n;
		
	}
	
	public static int getAllsum(ArrayList<Ball>ballInfos) {
		
		int sum =0;
		
		for(int i=0; i<ballInfos.size(); i++) { //ballInfos 안에 있는 모든 무게를 더해준다.
			
			sum += ballInfos.get(i).m;
			
		}
		return sum;
		
	}
	
	
	//ballinfos를 움직인 결과를 map에 넣고 map에서는 움직인 결과들을 계산해서 다시 ballInfos에 넣어주고 k가 0이 될 때까지 반복한다.
	public static void simulate(ArrayList<Ball>ballInfos) {
		
	for(int t=0; t<k; t++) { //상어들을 k만큼 움직여준다
		
		
		for(int i=0; i<ballInfos.size(); i++) { 
			
			int r = ballInfos.get(i).r; 
			int c = ballInfos.get(i).c;
			int m = ballInfos.get(i).m;
			int d = ballInfos.get(i).d;
			int s = ballInfos.get(i).s;
			
			int ns = s;
			int nr = r;
			int nc = c;
			
			
			while(ns>0) {
				nr += dx[d];
				nc += dy[d];
				if(!cango(nr,nc)) { /*어려웠던점1: 범위를 벗어났을때 연결된 행 or 열로 바꿔주는 것 -> 문제 제대로 안읽어서 이조건 고려 안함*/
					
					if(nr==0) {nr=n;} //만약 0 이되면 1행과 n행과 연결이 되어있으므로 nr을 n으로 바꿔준다.
					if(nr==n+1) {nr=1;} //만약 n+1이되면 n행과 1행이 연결도이어 있으므로 nr을 1로 바꿔준다.
					if(nc==0) {nc=n;}
					if(nc==n+1) {nc=1;}
				}
				ns--; //속도 거리만큼 빼준다.
				
			}

			
			map[nr][nc].add(new Ball(nr,nc,m,s,d)); //움직인 결과를 map에다가 넣어준다.
			
		}
		
		ballInfos.clear(); //기존에 있던 파이어볼 정보는 지운다.
		
		for(int i=1; i<=n; i++) { //map 을 탐색하면서 파이어볼이 있는 곳을 찾는다
			for(int j=1; j<=n; j++) {
				
				if(!map[i][j].isEmpty() && map[i][j].size()>=2) { //한칸에 여러개의 파이어볼이 있을 때
					
					int summ=0;
					int sums=0;
					boolean tg = true; //모두 짝 or 홀: true
					boolean prev = false;//홀수 false, 짝수 true
					
					ArrayList<Ball>arr = map[i][j];
					int sz = arr.size();
					
					for(int p=0; p<arr.size(); p++) {
						
						summ += arr.get(p).m; //질량을 모두 더해준다.
						sums += arr.get(p).s; //속력을 모두 더해준다.
						int dir = arr.get(p).d; //방향을 얻어온다
                        
                       //어려웠던점2: 모든 파이어볼의 방향이 홀수인지 짝수 인지 알아내는것 
						
						if(p==0) {
							prev = ((dir%2)==0); //이전 방향을 현재방향으로 바꿔주고 반복문 다시 시작
						}
						else {
							if(dir%2==0 && prev==false) { //현재 방향이짝수 인데 이전 방향은 홀수 인 경우 
								tg=false;
							} 
							else if(dir%2!=0 && prev==true) { //현재 방향이 홀수 인데 이전 방향은 짝수인 경우
								tg=false;
							}
							prev = ((dir%2)==0); //이전 방향을 현재방향으로 바꿔주고 반복문 다시 시작
						}
					
					}

					
					if(tg) { //모두 짝수 or 홀수 일때
						if((summ/5) !=0) {
						ballInfos.add(new Ball(i,j,summ/5,sums/sz,0)); //ballInfos에 저장해준다.
						ballInfos.add(new Ball(i,j,summ/5,sums/sz,2));
						ballInfos.add(new Ball(i,j,summ/5,sums/sz,4));
						ballInfos.add(new Ball(i,j,summ/5,sums/sz,6));
						}
					}
					else { //모두 짝수 or 홀수 아닐때
						if((summ/5) !=0) {
						ballInfos.add(new Ball(i,j,summ/5,sums/sz,1));
						ballInfos.add(new Ball(i,j,summ/5,sums/sz,3));
						ballInfos.add(new Ball(i,j,summ/5,sums/sz,5));
						ballInfos.add(new Ball(i,j,summ/5,sums/sz,7));
						}
					}
					map[i][j].clear(); //있던 파이어볼 지워준다.
				}
				else if(!map[i][j].isEmpty() && map[i][j].size()==1) { //해당 좌표에 있는 파이어볼이 한개일때
					
					if(map[i][j].get(0).m!=0) {
					ballInfos.add(map[i][j].get(0)); 
					}
					map[i][j].clear();
				}
				
				
			}
		}
		
	}
	}
	
	
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		st = new StringTokenizer(br.readLine());
		
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		k = Integer.parseInt(st.nextToken());
		
		ArrayList<Ball>ballInfos= new ArrayList<>();
		map = new ArrayList[n+1][n+1];
		
		for(int i=0; i<=n; i++) {
			for(int j=0; j<=n; j++) {
				map[i][j]=new ArrayList<>();
			}
		}
		
		
		for(int i=0; i<m; i++) {
			
			st = new StringTokenizer(br.readLine());
			ballInfos.add(new Ball(Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken())));
			//현재 파이어볼의 정보를 ballInfos에 저장
			
		}
		
		simulate(ballInfos); //파이어볼정보로 시뮬레이션
		int ans = getAllsum(ballInfos); //시뮬레이션 한 결과 무게 총합을 반환
		System.out.println(ans);
		
	}
	
	
}

어려웠던점1: 범위를 벗어났을때 연결된 행 or 열로 바꿔주는 것 -> 문제 제대로 안읽어서 이조건 고려 안함

어려웠던점2: 모든 파이어볼의 방향이 홀수인지 짝수 인지 알아내는것 

'백준 > 삼성기출' 카테고리의 다른 글

스타트택시 - 1923번(Java)  (0) 2021.09.18
어른상어 - 19237번 (JAVA)  (0) 2021.09.16
큐빙  (0) 2021.04.19
치킨 배달  (0) 2021.04.19
드래곤 커브  (0) 2021.04.18