문제

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

 

21608번: 상어 초등학교

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호

www.acmicpc.net

설명

 

4방향을 계속해서 체크해주면 되는 문제이며 아무 생각 없이 BFS를 떠올리지 말자

또한 여러 우선순위 조건이 있을 때는 Priority_queue를 쓰는 것도 좋은 방법인 것 같다.

 

마지막으로 for문 여러 개 중첩 시 순서를 잘 설계하고 코드 구현에 들어가자!! (+배열 인덱스 주의)

 

 

 

코드 

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
int N;
int map[21][21];
bool visited[21][21];
int dy[] = { -1,1,0,0 };
int dx[] = { 0,0,1,-1 };

struct Student {
	int num;
	int arr[4];

};
Student human[2000];
struct ABC {
	int blank;
	int like_num;
	int r;
	int c;

};
struct cmp {
	bool operator()(ABC a,ABC b) {
		//1,2,3 각각 우선순위 배정
		if (a.like_num == b.like_num) {

			if (a.blank == b.blank) {
				if (a.r == b.r) {
					return a.c > b.c;
				}

				return a.r > b.r;
			}
			return a.blank < b.blank;
		}
		return a.like_num < b.like_num;
	}
};
priority_queue<ABC, vector<ABC>, cmp> pq;
void findSit(int y,int x,int k) {
	int like_cnt = 0;
	int blank_cnt = 0;

	for (int i = 0; i < 4; i++) {
		int ny = y + dy[i];
		int nx = x + dx[i];
		if (ny < 0 || nx < 0 || ny >= N || nx >= N) continue;
		for (int j = 0; j < 4; j++) {
			if (map[ny][nx] == human[k].arr[j]) {
				like_cnt++;
			}
		}
		
		if (map[ny][nx] == 0) {
			blank_cnt++;
		}
	}

	pq.push({ blank_cnt,like_cnt,y,x });

}
int main() {
	cin >> N;

	for (int i = 0; i < N * N; i++) {
		cin >> human[i].num;
		for (int j = 0; j < 4; j++) {
			cin >> human[i].arr[j];
		}

	}

	for (int i = 0; i < N * N; i++) {
		for (int y = 0; y < N; y++) {
			for (int x = 0; x < N; x++) {
				if (map[y][x] == 0) {
					findSit(y, x,i);
				}
			}
			
		}
		map[pq.top().r][pq.top().c] = human[i].num; //자리배정완료 
		//pq초기화 까먹지말자
		while (!pq.empty()) {
			pq.pop();
		}

	}
	//만족도조사
	int answer = 0;
	
		for (int y = 0; y < N; y++) {
			for (int x = 0; x < N; x++) {
				int score = 0;
				for (int i = 0; i < N * N; i++) {
					if (map[y][x] == human[i].num) {

						for (int j = 0; j < 4; j++) {
							int ny = y + dy[j];
							int nx = x + dx[j];
							if (ny < 0 || nx < 0 || ny >= N || nx >= N) continue;
							for (int k = 0; k < 4; k++) {
								if (map[ny][nx] == human[i].arr[k]) {
									score++;
								}
							}
						}

					}
				}

				if (score == 1) answer += 1;
				if (score == 2) answer += 10;
				if (score == 3) answer += 100;
				if (score == 4) answer += 1000;

			}

		}



	


	cout << answer;

	return 0;
}

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

 

21608번: 상어 초등학교

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호

www.acmicpc.net

코드 설명 

지독한 구현 문제이다 삼성 문제는 구조체를 통해 담아두는 게 중요한 것 같다. 그리고 시간이 걸리더라도 설계를 최대한 상세하게 완벽하게 해 주는 것이 좋은 것 같다...(이번 문제 같은 경우 for문 속의 for문이 너무도 많기 때문에 작성하다가 놓친다)

 

우선순위 큐를 구현해서 문제에서 나온 우선순위대로 구현해준다.

map을 전체 탐색 하면서 0인 경우 들어가서 주변에 빈칸이 있는지++ , 좋아하는 친구가 있는지 ++ 체크해서 우선순위 큐에 넣어준다.

 

이후 마지막에 만족도 검사를 하면 된다

 

코드

#include<vector>
#include<iostream>
#include<queue>
using namespace std;
int dx[] = { -1,1,0,0 };
int dy[] = { 0,0,1,-1 };
int map[501][501];
bool visited[501][501];
struct human {
	int idx;
	int like[4];
	int y;
	int x;
};
struct pp {
	int y;
	int x;
	int blankcnt;
	int friendcnt;
};
struct cmp {
	bool operator()(pp a,pp b) {
		if (a.friendcnt == b.friendcnt) {
			if (a.blankcnt == b.blankcnt) {
				if (a.y == b.y) {
					return a.x > b.x;
				}
				return a.y > b.y;
			}
			
			return a.blankcnt < b.blankcnt;
		}

		return a.friendcnt < b.friendcnt;
	}

};
int jumsu[5] = { 0,1,10,100,1000 };
int N;
vector<human> child;
int main() {
	cin >> N;

	for (int i = 0; i < N * N; i++) {
		int a, b, c, d, e;
		cin >> a >> b >> c >> d >> e;
		child.push_back({ a,{b,c,d,e},0,0 });
		//놓일 자리 탐색	
		

	}

	for (int i = 0; i < child.size(); i++) {
	
		priority_queue<pp, vector<pp>, cmp> pq;
		for (int y = 0; y < N; y++) {
			for (int x = 0; x < N; x++) {
				if (map[y][x] == 0) {
					int blank_cnt = 0;
					int friend_cnt = 0;
					for (int k = 0; k < 4; k++) {
						int ny = y + dy[k];
						int nx = x + dx[k];
						if (ny < 0 || nx < 0 || ny >= N || nx >= N) continue;
						if (map[ny][nx] == 0) {
							blank_cnt++;
						}
						else {
							for(int j=0;j<4;j++){
								if (map[ny][nx] == child[i].like[j]) {
									friend_cnt++;
									break;
								}
							}
						}

					}


				pq.push({ y,x,blank_cnt,friend_cnt });
				}
			}
		}
		if (!pq.empty()) {
			int dy = pq.top().y;
			int dx = pq.top().x;
			
			map[dy][dx] = child[i].idx;
			child[i].y = dy;
			child[i].x = dx;

		}

	}

	//만족도 조사 
	int res = 0;
	for (int i = 0; i < N * N; i++) {
		int y = child[i].y;
		int x = child[i].x;

		int friends = 0;
		for (int k = 0; k < 4; k++) {
			int ny = y + dy[k];
			int nx = x + dx[k];
			if (ny < 0 || nx < 0 || ny >= N || nx >= N) continue;
			for (int j = 0; j < 4; j++) {
				if (map[ny][nx] == child[i].like[j]) {
					friends++;
					break;
				}

			}
		}
		res += jumsu[friends];
	}
	cout << res;


	return 0;
}

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

 

21610번: 마법사 상어와 비바라기

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기

www.acmicpc.net

코드 설명

이번 상반기 s사 기출문제이다... 분명 다풀었다고 생각했는데 자꾸 오류가나서 디버깅만 한시간했다...(함수형으로짜야 디버깅이 빠르다는걸 또 느꼈다...)

시험때 이러면 멘탈나가서 찾지도못할듯 -> 연산자 우선순위 생각!! 

 

우선 map이 전부 이어져 있다는 말은 결국 cycle처럼 0,1,2,3,4 가 있을때 5 는 0 이되고 -1은 4가 된다.

 

Move() 를통해 다음과 같이 cycle을 고려해주었다.

clouds[i].y += (dy[dir] * dis);
clouds[i].y %= N;

음수일 경우를 대비하여 각각 if (clouds[i].y < 0) clouds[i].y=(clouds[i].y + N) % N; 로 한번 더해준후 다시 나눠주는 tip!

 

그외 조심해야할 사항은 문제 똑바로 읽기! + visited배열과 같이 매번 가져다 쓰는거 초기화 잘해주기 !

 

코드

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
int dx[] = { -1,-1,0,1,1,1,0,-1 };
int dy[] = { 0,-1,-1,-1,0,1,1,1 };
int map[51][51];
bool visited[51][51];
int N, M;
int dir, dis;

struct cloud { // 구름좌표
	int y;
	int x;
};
vector<cloud> clouds;
void Move(int dir, int dis) {

	for (int i = 0; i < clouds.size(); i++) {
		clouds[i].y += (dy[dir] * dis);
		clouds[i].y %= N;
		if (clouds[i].y < 0) clouds[i].y=(clouds[i].y + N) % N;
		clouds[i].x += (dx[dir] * dis);
		clouds[i].x %= N;
		if (clouds[i].x < 0) clouds[i].x=(clouds[i].x + N) % N;

	}

}
void Rain() {
	for (int i = 0; i < clouds.size(); i++) {
		map[clouds[i].y][clouds[i].x]++;
		
	}


}
void bfs() {
	queue<pair<int, int>> q;
	for (int i = 0; i < clouds.size(); i++) {
		q.push({ clouds[i].y,clouds[i].x });
		
	}
	
	while (!q.empty()) {
		int y = q.front().first;
		int x = q.front().second;

		q.pop();

		int cnt = 0;
		for (int i = 1; i < 8; i+=2) {
			int ny = y + dy[i];
			int nx = x + dx[i];
			if (ny < 0 || nx < 0 || ny >= N || nx >= N) continue;
			if (map[ny][nx]!=0) {
				cnt++;
				
			}


		}
		map[y][x] += cnt;


	}

}
void check() {
	for (int y = 0; y < N; y++) {

		for (int x = 0; x < N; x++) {
			if (!visited[y][x] && map[y][x]>=2) {
				clouds.push_back({ y,x });
				map[y][x] -= 2;
			}

		}
	}



}
int main() {
	cin >> N >> M;
	for (int y = 0; y < N; y++) {
		for (int x = 0; x < N; x++) {
			cin >> map[y][x];
		}
	}
	//처음구름
	clouds.push_back({ N - 1,0 });
	clouds.push_back({ N - 2,0 });
	clouds.push_back({ N - 1,1 });
	clouds.push_back({ N - 2,1 });

	//구름 이동 입력 및 이동
	for (int i = 0; i < M; i++) {
		cin >> dir >> dis;
		dir--;
		
		//1.이동
		Move(dir, dis); 
		//2.비뿌리기(+1)
		Rain();
		//3.물복사버그 마법
		bfs();
		memset(visited, false, sizeof(visited));
		for (int i = 0; i < clouds.size(); i++) {
			visited[clouds[i].y][clouds[i].x] = true;
		}
		//3.구름 사라지기
		clouds.clear();
		//4.물의양이 2이상인 모든칸에 구름이 생기며 물의양-2 (기존 구름 제외)
		check();
		memset(visited, false, sizeof(visited));
		
	}

	int answer = 0;
	for (int y = 0; y < N; y++) {
		for (int x = 0; x < N; x++) {
			answer += map[y][x];
		}
	}

	cout << answer;
	return 0;
}

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

 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크

www.acmicpc.net

코드 설명

map과 copy_map으로 기존 맵과 다른 맵 하나를 만들어준다. 

map에 완전탐색을 통해 벽을 3개 만든다. 그때마다 copy_map으로 복사해주고 바이러스를 퍼뜨려본다.

그때마다 안전구역을 찾아주고 최대일 때를 저장해둔다.

 

다시 map으로 돌아와 다음 벽3개를 세워본다.

 

map에 벽세우기 -> copy_map 복사 -> copy_map 바이러스 감염 -> 안전구역 최대 개수 저장 -> 처음 map으로 돌아가기 

 

 

코드

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
int dy[] = { -1,1,0,0 };
int dx[] = { 0,0,1,-1 };
int map[10][10];
int copy_map[10][10];
bool visited[10][10];
int N, M;
int answer;
queue<pair<int, int>> q;
int result;
void bfs() {

	
	while (!q.empty()) {
		int y = q.front().first;
		int x = q.front().second;
		q.pop();

		for (int i = 0; i < 4; i++) {
			int ny = y + dy[i];
			int nx = x + dx[i];
			if (ny < 0 || nx < 0 || ny >= N || nx >= M) continue;
			if (!visited[ny][nx] && copy_map[ny][nx]!=1) {
				q.push({ ny,nx });
				visited[ny][nx] = true;
				copy_map[ny][nx] = 2; //감염 
			}
		}

	}


}

void dfs(int level,int y, int x) {

	if (level == 3) {
		memcpy(copy_map, map, sizeof(map));
		for (int y = 0; y < N; y++) {
			for (int x = 0; x < M; x++) {
				if (copy_map[y][x] == 2) {
					q.push({ y,x });
					
					visited[y][x] = true;
				}

			}
		}
		bfs();
		result = 0;
		for (int y = 0; y < N; y++) {
			for (int x = 0; x < M; x++) {
				if (copy_map[y][x] == 0) {
					result++;
					
				}

			}
		}
		answer = max(answer, result);
		memset(visited, false, sizeof(visited));
		

		return;

	}


	for (int y = 0; y < N; y++) {
		for (int x = 0; x < M; x++) {
			if (map[y][x]==0) {
				map[y][x] = 1; //벽세우기
				dfs(level + 1, y, x);
				map[y][x] = 0;
			}
		}
	}

}
int main() {
	cin >> N >> M;
	for (int y = 0; y < N; y++) {
		for (int x = 0; x < M; x++) {
			cin >> map[y][x];
		}
	}

	memcpy(copy_map, map, sizeof(map));

	//벽 3개 전부 세워보기
	dfs(0,0, 0);


	cout << answer;

	return 0;
}

+ Recent posts