[풀이]백준 풀이(XVI/11729 등)

문제풀이

아기상어(16236, 시뮬레이션 & BFS)

  • N*N 배열
  • 물고기 M마리 (한 칸에는 1마리만)
  • 아기상어 1마리
  • 상어, 물고기는 크기를 가지고 있다. (Tuple 사용?)

  • 상어는 크기 2로 시작, 1초에 상하좌우 1칸씩 이동가능 (dx, dy)

  • 더이상 먹을 수 있는 물고기가 없다면 아기상어는 엄마상어에게 도움을 청한다.
  • 먹을 수 있는 물고기가 1마리라면 그 물고기를 먹으러 간다.
  • 먹을 수 있는 물고기가 많다면 거리가 가장 가까운 물고기를 먹으러 간다.

  • 거리는 지나야하는 칸의 개수이다.
  • 거리가 같은 물고기가 있다면 가장위의 물고기를 그러한 물고기가 여러마리라면 가장 왼쪽에 있는 물고기를 먹는다.

(같은 거리에 있는 경우 왼쪽부터 ) (같은 높이에 여러마리 있는 경우 왼쪽부터)

«^ »^ »> 이렇게 있으면

  • 아기상어가 엄마에게 도움을 청할때 까지 걸리는 시간.

  • 왔던 곳을 다시 방문할 수 있다. 물고기를 잡아먹은 곳에서 함수를 실행해서 가능한지 안한지 판별 반복한다.

물고기 피해가는거 구현,,,, 크기가 같은 물고기는 지나갈 수 있다

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <tuple>

#define INF 987654321

using namespace std;
int map[21][21];
int Answer = 0;
int n, jawsSize = 2, currentJawsX, currentJawsY, currentFishX, currentFishY;
int eaten = 0, minDist = INF, minDistTemp, compare;
int dx[] = { 0, 0, -1, 1 };
int dy[] = { 1,-1,  0, 0 };
int bfsDist[21][21];
bool visited[21][21];
queue<pair<int, int>> nxt;

void init() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			map[i][j] = -1;
			bfsDist[i][j] = -1;
			visited[i][j] = false;
		}
	}
}
bool isSizeup() {
	if (eaten == jawsSize) return true;
	else return false;
}
bool isInside(int x, int y) {
	if (x >= 0 && y >= 0 && x < n && y < n) return true;
	else return false;
}
bool isEmpty() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (map[i][j] > 0) {
				//상어가 아닌 0이상의 정수(물고기)가 하나라도 있으면 false
				if (map[i][j] != 9) return false;
			}
		}
	}
	return true;
}
bool isNext(int origin, int compare) {
	//비교한 거리가 더 가까우면 후보변경
	if (origin >= compare) return true;
	else return false;
}
int calcDist(int i, int j) {
	//상어와 물고기의 맨하탄 디스탄스 리턴
	int x = abs(currentJawsX - i);
	int y = abs(currentJawsY - j);
	return x + y;
}
//물고기를 찾는다.
//만약 없다면-> 엄마상어 호출 or 다먹은 경우(isEmpty)
//만약 있다면-> 어떤 물고기 먹을지 고르는 함수();
//반복주기 -> findFish() -> selectFish() -> isSizeup()
void printMap() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cout << map[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
}
void bfs(int sx, int sy) {
	queue<pair<int, int>> q;
	q.push(make_pair(sx, sy));
	visited[sx][sy] = true;
	while (!q.empty()) {
		int cx = q.front().first;
		int cy = q.front().second;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int nx = cx + dx[i];
			int ny = cy + dy[i];
			//방문한 적 없고,
			if (!visited[nx][ny] && isInside(nx, ny)) {
				//지나갈 수 있으면
				if (jawsSize >= map[nx][ny]) {
					q.push(make_pair(nx, ny));
					visited[nx][ny] = true;
					bfsDist[nx][ny] = bfsDist[cx][cy] + 1;
				}
			}
		}
	}
}
void selectFish() {
	minDist = INF;
	minDistTemp = minDist;
	//init visited;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			visited[i][j] = false;
			bfsDist[i][j] = 0;
		}
	}
	bfs(currentJawsX, currentJawsY);

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			//물고기이고
			if (map[i][j] > 0) {
				//상어가아니고
				if (map[i][j] != 9) {
					//상어보다 작은 물고기이며 범위안이며니
					if (map[i][j] < jawsSize) {
						if (isInside(i, j)) {
							//만약 [i][j]를 갈 수 잇으면
							if (visited[i][j]) {
								//거리를 계산한 뒤
								//가까운지를 확인하고(거리가 작거나 같음)
								if (minDist > bfsDist[i][j]) {
									//거리의 최소값을 갱신한다.
									minDist = min(minDist, bfsDist[i][j]);
									//만약 거리가 작다면 잡아먹을 물고기후보 변경!
									currentFishX = i;
									currentFishY = j;
								}
								//만약 이전 최소와 거리가 같다면
								else if (minDist == bfsDist[i][j]) {
									//가장 위인지 비교 
									//만약 다음물고기가 더 위라면
									if (currentFishX > i) {
										currentFishX = i;
										currentFishY = j;
									}
									//만약 둘의 높이가 같다면
									else if (currentFishX == i) {
										//좌 우를 비교하여 잡아먹을 물고기후보 변경!
										if (currentFishY > j) {
											currentFishX = i;
											currentFishY = j;
										}
									}
								}
							}
						}
						//예외(거리1)
					}
				}
			}
		}
	}
}

void findFish(int x, int y, int size) {
	currentJawsX = x;
	currentJawsY = y;
	//물고기위치도 처음위치로 가자.
	currentFishX = INF;
	currentFishY = INF;
	if (isEmpty()) {
		return;
	}
	//사이즈가 커져야하면
	if (isSizeup()) {
		jawsSize++;
		eaten = 0;
	}

	//모든점을 돌아 최소거리의 물고기를 선택한 상태
	selectFish();
	//다 돌았는데 고를 수 있는 물고기가 없다?
	if (INF == currentFishX && INF == currentFishY) {
		return;
	}
	else {
		Answer += bfsDist[currentFishX][currentFishY];
		//원래 상어가 있던 자리를 0으로 변경하고
		map[currentJawsX][currentJawsY] = 0;
		//물고기 잡아먹기
		currentJawsX = currentFishX;
		currentJawsY = currentFishY;

		//상어 위치변경과 먹은 수 증가
		map[currentJawsX][currentJawsY] = 9;
		eaten++;
		//새로 탐색
		findFish(currentJawsX, currentJawsY, size);
	}
}

int main() {

	cin >> n;
	//초기화
	init();
	int x, y;
	//우선순위  크기 > 거리 > 높이 > 왼쪽
	//상어크기는 자신과 크기가 같은 수의 물고기를 먹을 때 1증가한다.
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> map[i][j];
			if (map[i][j] == 9) {
				x = i;
				y = j;
			}
		}
	}
	findFish(x, y, jawsSize);
	cout << Answer << endl;
}

유기농 배추(1012, BFS)

  • 지렁이는 배추근처에 서식하며 해충을 잡아먹는다.
  • 어떤 배추에 지렁이가 있는 경우 지렁이는 인접한 칸으로 이동할 수 있다. (상,하,좌,우)
  • 배추들이 곳곳에 퍼져있을 때 필요한 지렁이의 최소마리수

풀이

단순 그룹화를 하는 문제이다. ezez

#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;

int test_case, m, n, k,group=0;
int map[51][51];
int dist[51][51];
int dx[] = {0, 0, 1, -1};
int dy[] = {1,-1, 0,  0};
bool visited[51][51];

bool isInside(int x, int y){
	if(x>=0 && y>=0 && x<n && y<m) return true;
	else return false;
}
void init(){
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++){
			map[i][j] = 0;
			dist[i][j] = 0;
			visited[i][j] = false;
			group = 0;
		}
	}
}
void printMap(){
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++){
			cout << map[i][j] << " ";
		}
		cout << endl;
	}
}

void bfs(int sx, int sy){
	queue<pair<int,int>> q;
	q.push(make_pair(sx,sy));
	visited[sx][sy] = true;

	while(!q.empty()){
		int cx, cy;
		cx = q.front().first;
		cy = q.front().second;
		q.pop();
		for(int i=0; i<4; i++){
			int nx = cx + dx[i];
			int ny = cy + dy[i];
			if(!visited[nx][ny] && map[nx][ny]==1 && isInside(nx,ny)){
				q.push(make_pair(nx,ny));
				visited[nx][ny]=true;
			}
		}
	}
}
int main(){
	cin >> test_case;
	for(int i=0; i<test_case; i++){
		//초기화
		init();
		//m=가로길이, n=세로길이, k=배추 갯수
		cin >> m >> n >> k;

		//배추 세팅
		for(int a=0; a<k; a++){
			int x, y;
			cin >> x >> y;
			map[y][x] = 1;
		}

		for(int a=0; a<n; a++){
			for(int b=0; b<m; b++){
				if(map[a][b]>0 && !visited[a][b]) {
					bfs(a,b);
					group++;
				}
			}
		}
		cout << group << endl;
	}
}

[RE]경로 찾기(11403, DFS/BFS)

  • 가중치 없는 방향 그래프 G
  • 모든 정점(i,j)에 대해 i to j가 가능한지 구하는 프로그램을 작성

회고

  • BFS로 하다가 뻘짓을 많이했다..
  • DFS가 훨씬 편한데.. BFS로 다시 풀어보긴하자
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;

int n;
int graph[100][100];
int visited[100];
int result[100][100];

void initVisit(){
	for(int i=0; i<n; i++){
		visited[i]=0;
	}
}
void init(){
	for(int i=0; i<n; i++){
		for(int j=0; j<n; j++){
			graph[i][j] = 0;
			result[i][j] = 0;
		}
	}
}
//반복을 많이하네
void dfs(int s){
	for(int i=0; i<n; i++){
		if(graph[s][i]>0 && !visited[i]){
			visited[i]++;
			dfs(i);
		}
	}
}
int main(){
	ios_base :: sync_with_stdio(false);
	cin.tie(NULL);


	cin >> n;
	for(int i=0; i<n; i++){
		for(int j=0; j<n; j++){
			cin >> graph[i][j];
		}
	}

	for(int i=0; i<n; i++){
		initVisit();
		dfs(i);

        for(int j=0;j<n;j++){
            if(visited[j])
                graph[i][j]=1;
        }
	}

	cout << "\n";
	for(int i=0; i<n; i++){
		for(int j=0; j<n; j++){
			cout << graph[i][j] << " ";
		}
		cout << "\n";
	}
}

나무 재테크(16235)

  • N*N크기의 땅 구매 (r,c)로 위치표기
  • r>=1 c>=1
  • 땅의 기본 양분은 5이다.
  • 땅에 M개의 나무를 심는다.
  • (한 칸에 여러그루의 나무가 있을 수도 있다.)

  • 나무가 자신의 나이만큼 양분을 먹고 나이가 1 증가한다.
  • 여러그루의 나무가 있을 경우 어린나무부터 양분을 먹는다.
  • 양분이 부족할 경우 나무는 즉시 죽는다.

여름

  • 봄에 죽은 나무가 영양분으로 변한다.(죽은 나무의 나이 /2, 버림연산)

가을

  • 나이가 5의 배수인 나무가 번식한다.
  • 번식할 경우 인접한 8칸에 나이가 1인 나무가 생긴다.

겨울

  • 로봇이 돌아다니며 양분을 추가한다. A[r][c]만큼씩 추가.

K년이 지난 후 살아있는 나무의 개수는?

tip - tuple은 정렬이 어렵다.

#include <iostream>
#include <queue>
#include <vector>
#include <tuple>
#include <algorithm>
#include <cmath>
using namespace std;

int n, m, k;
int dx[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
int dy[] = { -1,  0,  1,-1, 1,-1, 0, 1 };
//<x, y, age>
vector<int> tree[10][10];
vector<int> treeTemp[10][10];
queue<tuple<int, int, int>> forAdd;
queue<tuple<int, int, int, int>> forNut;
//땅-양분정보
int treeCount[10][10];
int nut[10][10];
//1년이 지날 때마다 추가될 양분
int a[10][10];

void init() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			//기본양분 세팅
			nut[i][j] = 5;
			a[i][j] = 0;
		}
	}
}
void addNut() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			nut[i][j] += a[i][j];
		}
	}
}
int calcTree() {
	int Answer = 0;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			int treeSize = tree[i][j].size();
			if (treeSize > 0) {
				for (int k = 0; k < tree[i][j].size(); k++) {
					if (tree[i][j].at(k) > 0) {
						Answer++;
					}

				}
			}
		}
	}
	return Answer;
}
bool isInside(int x, int y) {
	if (x >= 0 && y >= 0 && x < n && y < n) return true;
	else return false;
}
void afterYear() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			int treeSize = tree[i][j].size();
			if (treeSize > 0) {
				//소팅부터해놓고 (나이가 어린 나무부터 처리하기 위해서)
				sort(tree[i][j].begin(), tree[i][j].end());
				for (int k = 0; k < treeSize; k++) {
					//각 칸에 위치한 나무만큼 반복

					//양분이 충분할 경우  && 죽지않은 나무에 한해서 (봄)
					//tree[i][j].at(k) = (i,j)에 위치한 k번째 (나이순) 나무의 나이
					if (nut[i][j] >= tree[i][j].at(k) && tree[i][j].at(k) > 0) {
						nut[i][j] -= tree[i][j].at(k);
						tree[i][j].at(k)++;

						//(가을)살아남아야만 번식이가능하므로
						if (tree[i][j].at(k) % 5 == 0 && tree[i][j].at(k) != 0 ) {
							for (int l = 0; l < 8; l++) {
								//인접한 방향에 1짜리 나무를 집어넣는다
								if (isInside( i + dx[l], j + dy[l] )) {
									forAdd.push(tuple<int, int, int>(i + dx[l], j + dy[l], 1));
								}
							}
						}
					}
					//죽음
					else {
						//양분보충
						forNut.push(tuple<int, int, int, int>(i , j, floor(tree[i][j].at(k) / 2), k));
					}
				}
				//양분이 부족한 경우 (여름)
				while (!forNut.empty()) {
					int ti, tj, ta, tk;
					tie(ti, tj, ta, tk) = forNut.front();
					forNut.pop();
					nut[ti][tj] += ta;
					tree[ti][tj].pop_back();
					//tree[ti][tj].at(tk) = 0;
				}
			}
		}
	}
	//가을 번식
	while (!forAdd.empty()){
		int ti, tj, tk;
		tie(ti, tj, tk) = forAdd.front();
		forAdd.pop();
		tree[ti][tj].push_back(tk);
	}
	//겨울.. 
	addNut();
}


int main() {
	ios_base::sync_with_stdio(false); 
	cin.tie(NULL); 
	cout.tie(NULL);
	//n =땅크기, m = 나무수, k= 지난 연도수
	cin >> n >> m >> k;
	//초기화
	init();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> a[i][j];
		}
	}
	for (int i = 0; i < m; i++) {
		int x, y, age;
		cin >> x >> y >> age;
		tree[x-1][y-1].push_back(age);
	}
	for (int i = 0; i < k; i++) {
		afterYear();
	}
	cout << calcTree() << endl;
}

댓글남기기