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

 

17281번: ⚾

⚾는 9명으로 이루어진 두 팀이 공격과 수비를 번갈아 하는 게임이다. 하나의 이닝은 공격과 수비로 이루어져 있고, 총 N이닝동안 게임을 진행해야 한다. 한 이닝에 3아웃이 발생하면 이닝이 종료되고, 두 팀이 공격과 수비를 서로 바꾼다. 두 팀은 경기가 시작하기 전까지 타순(타자가 타석에 서는 순서)을 정해야 하고, 경기 중에는 타순을 변경할 수 없다. 9번 타자까지 공을 쳤는데 3아웃이 발생하지 않은 상태면 이닝은 끝나지 않고, 1번 타자가 다시 타석에

www.acmicpc.net

선수 9명의 순서를 결정해야 한다. 4번 타자는 1번 선수로 고정되어 있기 때문에 이를 반영해준다.

 

이닝별로 선수들의 결과를 입력으로 받는다.

 

따라서 모든 순열을 구해서 선수들의 순서를 만들어낸 이후에, 야구의 조건을 구현해주면 된다.

 

 

1루, 2루 등에 진출해 있는 선수들에 대한 관리는, 선수 번호를 그대로 인덱스로 해서 배열을 두었다.

 

1이면 1루에 있다는 뜻이고, 2면 2루 3이면 3루에, 

4 이상이 되면 홈으로 들어왔다는 의미이다.

 

각 이닝별로 선수들의 수행을 그대로 따라가면서 시뮬레이션을 진행해주면 된다.

 

res[][] 배열은 이닝별 선수의 득점이다.

 

num은 1~9까지 선수들 중에 9명을 뽑는 경우의 수로 사용한다.

 

ord는 뽑아서 결정된 선수들의 순서이다. ord[i]는 i번 타자를 의미한다.

 

#include<iostream> //2백만
#include<vector>
using namespace std;
int n, res[52][10], num[10], ord[10], pos[10], Max = -1;
bool isused[10];
void play() {
	int hitter = 1, score = 0;
	for (int i = 1; i <= n; i++) { //i이닝에
		int outCnt = 0;

		while (1) {
			if (res[i][ord[hitter]] == 0) { //아웃인 경우
				hitter++;
				if (hitter >= 10) hitter = 1;
				outCnt++;
				if (outCnt == 3) {
					//이닝 교체
					for (int j = 1; j <= 9; j++) pos[j] = 0;
					break;
				}
			}
			else {
				//득점타
				for (int j = 1; j <= 9; j++) {
					if (pos[j] > 0 || j == ord[hitter]) { //타석에 나가 있는 선수라면
						pos[j] += res[i][ord[hitter]];
						if (pos[j] >= 4) {
							//홈에 들어오면
							pos[j] = 0;
							score++;
						}
					}
				}
				hitter++;
				if (hitter >= 10) hitter = 1;
			}
		}
	}
	if (Max < score) Max = score;
}
void func(int k) {
	if (k > 9) { //base condition
		play();
		return;
	}
	for (int i = 2; i <= 9; i++) {
		if (!isused[i]) {
			ord[k] = i;
			isused[i] = true;
			if (k == 3) func(k + 2); //3번엔 다음 4번이 아니라 5번을 정함
			else func(k + 1);
			isused[i] = false;
		}
	}
}
int main(void) {
	for (int i = 1; i <= 9; i++)
		num[i] = i;
	isused[1] = true; //1은 항상 사용중
	ord[4] = 1; // 4번 선수는 항상 1
	cin >> n;
	
	for (int i = 1; i <= n; i++) 
		for (int j = 1; j <= 9; j++) 
			cin >> res[i][j];
	
	func(1);
	cout << Max << '\n';
	return 0;
}

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

 

17144번: 미세먼지 안녕!

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다. 공기청정기는 항상 왼쪽 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼

www.acmicpc.net

 

약간의 bfs와 시뮬레이션이 혼합된 문제이다.

 

입력을 받은 이후에, 먼지가 있는 곳을 미리 큐에 넣어준다. 동시에 확산되어야 한다는 조건이 있기 때문이다.

 

미리 큐에 넣어주고, 한 번 탐색을 했을 때 큐의 크기만큼만 확산을 진행하면 단위 시간이 흘렀다고 볼 수 있다.

 

그리고, 이전에 발생했던 먼지의 확산이, 앞으로 발생하게 될 먼지의 확산에 영향을 끼치지 않게 하기 위해서

 

변화량을 따로 저장한 이후에, 확산을 마치고 변화량을 모두 구한 이후에 한꺼번에 반영해줘야 한다.

 

그렇지 않으면 동시에 확산했다는 조건을 만족시킬 수 없기 때문이다.

 

 

다음으로 환기에 대한 조건을 구현할 때는, 조건에 맞게 인덱스를 가지고 놀아주면 된다.

 

한 가지 주의할 사항은, 환기의 순서를 신경 써야 한다는 것이다.

 

먼저 빨려들어가서 없어지는 먼지의 값을 덮어 씌워주는 방향으로 순서를 정해야, 중간에 다른 구석 지점에서 먼지의 값이 누락되는 것을 방지할 수 있다.

 

따라서 먼저 빨려들어가는 쪽에 대한 처리를 먼저 해주는 방식으로 구현한다.

 

#include<iostream>
#include<queue>
using namespace std;
int m[52][52], T, R, C, dif[52][52];
bool vis[52][52];
pair<int, int> Up;
pair<int, int> Dn;
queue<pair<int, int> > q;
int dr[4] = { 0,0,1,-1 };
int dc[4] = { 1,-1,0,0 };
void clean() {
	//상부
	for (int i = 1; i <= Up.first - 1; i++)  //하향
		m[Up.first - i][0] = m[Up.first - 1 - i][0];
	for (int i = 0; i <= C - 2; i++) //좌향
		m[0][i] = m[0][i + 1];
	for (int i = 0; i <= Up.first - 1; i++) //상향
		m[i][C - 1] = m[i + 1][C - 1];
	for (int i = C - 1; i >= 1; i--) //우향
		m[Up.first][i] = m[Up.first][i - 1];


	//하부
	for (int i = Dn.first + 1; i <= R - 2; i++) //상향
		m[i][0] = m[i + 1][0];
	for (int i = 1; i <= C - 1; i++) //좌향
		m[R - 1][i - 1] = m[R - 1][i];
	for (int i = R - 1; i >= Dn.first + 1; i--)//하향
		m[i][C - 1] = m[i - 1][C - 1];

	for (int i = C - 1; i >= 1; i--) //우향
		m[Dn.first][i] = m[Dn.first][i - 1];
}

void bfs() {
	int cnt = q.size();
	while (cnt--) {
		pair<int, int> cur = q.front();
		q.pop();
		for (int i = 0; i < 4; i++) {
			int nr = cur.first + dr[i];
			int nc = cur.second + dc[i];
			if (nr < 0 || nc < 0 || nr >= R || nc >= C ) continue;
			if (nr == Up.first && nc == Up.second) continue;
			if (nr == Dn.first && nc == Dn.second) continue;
			
			dif[cur.first][cur.second] -= m[cur.first][cur.second] / 5;
			dif[nr][nc] += m[cur.first][cur.second] / 5;
		}
	}
	//update
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			m[i][j] += dif[i][j];
		}
	}
	//Print();
	clean();
}
void init() {
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			vis[i][j] = false;
			dif[i][j] = 0;
		}
	}
}
int main(void) {
	cin >> R >> C >> T;
	bool fst = true;
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			cin >> m[i][j];
			if (m[i][j] == -1) {
				m[i][j] = 0;
				if (fst) {
					Up.first = i;
					Up.second = j;
					fst = false;
				}
				else {
					Dn.first = i;
					Dn.second = j;
				}
			}
		}
	}
	
	//1초 루틴
	while (T--) {
		for (int i = 0; i < R; i++) {
			for (int j = 0; j < C; j++) {
				if (m[i][j] != 0 && !vis[i][j]) { //방문 조건도 사실 필요없음
					q.push({ i, j });
					vis[i][j] = true;
				}
			}
		}
		bfs();
		init();
	}
	int Sum = 0;
	for (int i = 0; i < R; i++)
		for (int j = 0; j < C; j++)
			Sum += m[i][j];
	cout << Sum << '\n';
	return 0;
}

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

 

13335번: 트럭

문제 강을 가로지르는 하나의 차선으로 된 다리가 하나 있다. 이 다리를 n 개의 트럭이 건너가려고 한다. 트럭의 순서는 바꿀 수 없으며, 트럭의 무게는 서로 같지 않을 수 있다. 다리 위에는 단지 w 대의 트럭만 동시에 올라갈 수 있다. 다리의 길이는 w 단위길이(unit distance)이며, 각 트럭들은 하나의 단위시간(unit time)에 하나의 단위길이만큼만 이동할 수 있다고 가정한다. 동시에 다리 위에 올라가 있는 트럭들의 무게의 합은 다리의 최

www.acmicpc.net

 

다리의 상태와 트럭의 상태를 나타내야 한다.

 

다리의 경우, 지금 버티고 있는 무게가 몇인지 그리고 현재 다리 위에 몇 개의 트럭이 올라와 있는지를 항상 유지해야 한다.

 

트럭의 경우에는, 각 트럭 별로 트럭의 무게, 그리고 다리 위에 있는지 여부, 그리고 다리 위에 존재한 시간(혹은 거리)을 유지해야 한다.

 

따라서 위와 같은 조건을 나타내기 위해서 구조체를 사용했다.

 

무한 루프를 만들고, 마지막 차가 다리를 탈출하는 순간을 루프 탈출 조건으로 잡았다.

 

#include<iostream>
using namespace std;
struct Bridge { 
	int wei = 0; //다리에 가해진 무게
	int cnt = 0; //다리위 차의 개수
};
struct Car {
	int wei = 0; //차의 무게
	int time = 0;//차의 이동 시간(거리)
	bool onBri = false; //차가 다리위에 있는지 여부
};
Car car[2000];
Bridge brg;
int n, len, lim; //차의 개수, 다리의 길이, 하중 제한
int main(void) {
	cin >> n >> len >> lim;
	for (int i = 0; i < n; i++)
		cin >> car[i].wei;
	brg.cnt = 0;
	brg.wei = 0;
	int idx = 0, Time = 0; //다리위에 올라가는 차의 인덱스, 전체 시간
	bool endFlag = false;
	while (1) {
	
		//다리 위의 차들 이동(시간 증가)
		for (int i = 0; i < n; i++) {
			if (car[i].onBri) {
				car[i].time++;
				//printf("%d번 차 움직인 거리: %d\n", i, car[i].time);
				if (car[i].time >= len) {
					if (i == n - 1) {
						//다리를 벗어나는 차가 마지막 차라면
						endFlag = true;
						Time++;
						break;
					}
					//이 차가 다리를 다 건너면
					brg.cnt--;
					brg.wei = brg.wei - car[i].wei;
					car[i].onBri = false;
				}
			}
		}

		if (endFlag) break;

		if (lim - brg.wei >= car[idx].wei && brg.cnt < len) {
			//가능한 무게이면서 다리위에 공간이 남았으면
			car[idx].onBri = true;
			brg.wei = brg.wei + car[idx].wei;
			idx++;
			brg.cnt++;
		}
		Time++;
	}
	cout << Time << '\n';
	return 0;
}

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

 

14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지도에 쓰여 있는 수가 북쪽부터 남쪽으로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 주사위를 놓은 칸에 쓰여 있는 수는 항상 0이다. 지도의 각 칸에 쓰여 있는 수는 10을 넘지 않는 자연수 또는 0이다. 마

www.acmicpc.net

먼저 주사위의 동, 서, 남, 북, 위, 아래를 배열 인덱스의 0~5까지로 대응시킨다.

 

명령을 하나씩 받아서, 먼저 이동할 수 있는지 판단한다. 동쪽이면 동쪽으로 벗어날 것이고, 남쪽이면 남쪽으로 벗어날 것이고 이런 식으로 확인할 수 있다.

 

지도를 벗어나지 않는다면, 명령에 맞춰서 주사위를 회전해주면 된다. 회전 방향에 따라 주사위의 상태를 갱신해주고, 주사위의 위치를 변경해준다.

 

이후에 조건에 맞게 출력을 해주면 된다.

 

#include<iostream>
using namespace std;
int dice[6];
int Row, Col, srcR, srcC, cnt, m[20][20];
void Move(int dir) {
	int temp;
	if (dir == 1) { //동쪽으로 굴릴 때
		if (srcC + 1>= Col) return;
		//주사위 회전, 좌표 이동
		//남2 북3 그대로
		temp = dice[0];
		dice[0] = dice[4];
		dice[4] = dice[1];
		dice[1] = dice[5];
		dice[5] = temp;
		srcC++;
	}
	else if (dir == 2) { //서
		if (srcC - 1 < 0) return;
		temp = dice[1];
		dice[1] = dice[4];
		dice[4] = dice[0];
		dice[0] = dice[5];
		dice[5] = temp;
		srcC--;
	}
	else if (dir == 3) { //북
		if (srcR - 1 < 0) return;
		temp = dice[3];
		dice[3] = dice[4];
		dice[4] = dice[2];
		dice[2] = dice[5];
		dice[5] = temp;
		srcR--;
	}
	else { //남
		if (srcR + 1 >= Row) return;
		temp = dice[2];
		dice[2] = dice[4];
		dice[4] = dice[3];
		dice[3] = dice[5];
		dice[5] = temp;
		srcR++;
	}
	if (m[srcR][srcC] == 0) {
		m[srcR][srcC] = dice[5];
	}
	else {
		dice[5] = m[srcR][srcC];
		m[srcR][srcC] = 0;
	}
	cout << dice[4] << '\n';
}
int main(void) {
	
	cin >> Row >> Col >> srcR >> srcC >> cnt;
	for (int i = 0; i < Row; i++) {
		for (int j = 0; j < Col; j++) {
			cin >> m[i][j];
		}
	}
	while (cnt--) {
		int op;
		cin >> op;
		Move(op);
	}
	return 0;
}

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

 

1547번: 공

첫째 줄에 컵의 위치를 바꾼 횟수 M이 주어지며, M은 50보다 작거나 같은 자연수이다. 둘째 줄부터 M개의 줄에는 컵의 위치를 바꾼 방법 X와 Y가 주어지며, X번 컵과 Y번 컵의 위치를 서로 바꾸는 것을 의미한다. 컵을 이동시키는 중에 공이 컵에서 빠져나오는 경우는 없다. X와 Y의 값은 3보다 작거나 같고, X와 Y가 같을 수도 있다.

www.acmicpc.net

arr[0]에 공이 있다고 정해둔다.

 

arr에 1,2,3을 초기에 순서대로 담아두고, 값이 컵의 번호라고 생각하고 들어오는 숫자의 인덱스를 구해서 두 인덱스에 해당하는 arr값을 스왑해준다.

 

#include<iostream>
using namespace std;
int m, arr[3] = { 1,2,3 };
int main(void) {
	cin >> m;

	while (m--) {
		int num1, num2, idx1, idx2;
		cin >> num1 >> num2;
		for (int i = 0; i < 3; i++) {
			if (arr[i] == num1) idx1 = i;
			if (arr[i] == num2) idx2 = i;
		}
	
		int temp = 0;
		temp = arr[idx1];
		arr[idx1] = arr[idx2];
		arr[idx2] = temp;
	}
	cout << arr[0] << '\n';

	return 0;
}

+ Recent posts