www.acmicpc.net/problem/2638

 

2638번: 치즈

첫째 줄에는 모눈종이의 크기를 나타내는 두 개의 정수 N, M (5≤N, M≤100)이 주어진다. 그 다음 N개의 줄에는 모눈종이 위의 격자에 치즈가 있는 부분은 1로 표시되고, 치즈가 없는 부분은 0으로 표

www.acmicpc.net

1. 풀이방법

 

- 문제를 보면 bfs를 이용해야 겠다는 생각이 들고,

 

- 처음에 딱 핵심이다 라고 생각되는 것은 0(빈칸) 중에서 외부공기 / 실내공기 를 나누어 주어야 한다는 것.

 

- 그리고 문제설정에서 외부공기는 반드시 존재하게끔 되어있습니다.

 

- 바로 "모눈종이의 맨 가장자리에는 치즈가 놓이지 않는 것으로 가정한다" 적어도, 4자리는 외부공기라는 것

 

- 그래서 처음에 이 4점을 기준으로 bfs를 돌려 외부공기를 모두 2로 표시해주고 시작합니다.

 

- 저 같은 경우 벡터에 치즈의 자리를 모두 넣은 뒤, 이 치즈들이 사라질 때마다 이 자리들을 다시 큐에 넣어

 

- 이 치즈가 녹음으로써 내부공기 -> 외부공기 가 되는 것들을 체크해주었습니다.

 

 

 

 

2. 주의사항

 

- 이런 류의 문제에서 사라지는 c의 위치를 찾았을 때 바로 ground를 2로 바꿔버리면 그 뒤의 치즈들이 이 것에 의해

 

- 영향을 받을 수 있습니다. 그래서 벡터의서 check를 true로만 바꿔주고, 작업이 끝난뒤에

 

- check가 true인 것들을 한번에 2로 바꾸어주었습니다.

 

 

 

3. 나의코드

#include<bits/stdc++.h>
using namespace std;

int n, m;
//1은 치즈 , 0 은 빈칸 , 2는 실외공기
int ground[101][101];
bool visited[101][101];
int cheesecount = 0;
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
struct cheese {
	int cx, cy;
	bool check;
};
vector<pair<int, int>> sideindex;
queue<pair<int, int>> tmpq;
vector<cheese> tmpv;

void inputs() {
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> ground[i][j];
			if (ground[i][j] == 1) {
				cheesecount++; tmpv.push_back({ i,j,false });
			}
		}
	}
	sideindex.push_back({ 0, 0 }); sideindex.push_back({ n - 1,0 });
	sideindex.push_back({ 0,m - 1 }); sideindex.push_back({ n - 1,m - 1 });
}
bool boundcheck(int x, int y) {
	if (x >= 0 && x < n && y >= 0 && y < m) return true;
	else return false;
}
void makeoutside() {
	while (!tmpq.empty()) {
		int qsize = tmpq.size();
		while (qsize--) {
			int nextx = tmpq.front().first;
			int nexty = tmpq.front().second;
			tmpq.pop();
			for (int i = 0; i < 4; i++) {
				int tx = nextx + dx[i]; int ty = nexty + dy[i];
				if (boundcheck(tx, ty) && visited[tx][ty] == false && ground[tx][ty] != 1) {
					visited[tx][ty] = true;
					tmpq.push({ tx,ty });
					ground[tx][ty] = 2;
				}
			}
		}
	}
}


int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	inputs();
	int second = 0;		
	//실외공기 구하기
	for (int i = 0; i < 4; i++) {
		visited[sideindex[i].first][sideindex[i].second] = true;
		ground[sideindex[i].first][sideindex[i].second] = 2;
		tmpq.push(sideindex[i]);
	}
	
	makeoutside();
	while (1) {
		if (cheesecount == 0) break;
		for (int i = 0; i < tmpv.size(); i++) {
			if (tmpv[i].check == true) continue;
			int vsize = 0;
			for (int j = 0; j < 4; j++) { //4방향 탐색
				if (ground[tmpv[i].cx + dx[j]][tmpv[i].cy + dy[j]] == 2) {
					vsize++;
				}
				if (vsize >= 2) {
					cheesecount--;
					visited[tmpv[i].cx + dx[j]][tmpv[i].cy + dy[j]] = true;
					tmpv[i].check = true; //여기는 없어짐
					tmpq.push({ tmpv[i].cx + dx[j],tmpv[i].cy + dy[j] });
					break;
				}
			}
		}
		for (int i = 0; i < tmpv.size(); i++) {
			if (tmpv[i].check == true) {
				ground[tmpv[i].cx][tmpv[i].cy] = 2;
			}
		}
		makeoutside(); //없어진 치즈로 인해 실내공기에서 외부공기가 되는 녀석들 체크
		second++;
	}
	cout << second;
	return 0;
}

'알고리즘 문제풀이 > DFS와 BFS' 카테고리의 다른 글

백준 15900 [C++]  (0) 2021.01.19
백준 2251 [C++]  (0) 2021.01.19
백준 1600 [C++]  (0) 2021.01.19
백준 12851 [C++]  (0) 2021.01.18
백준 13913 [C++]  (0) 2021.01.18

www.acmicpc.net/problem/15900

 

15900번: 나무 탈출

평소에 사이가 좋지 않던 성원이와 형석이가 드디어 제대로 한 판 붙으려고 한다. 성원이와 형석이 둘과 모두 똑같이 친한 인섭이가 대결 종목을 정해 가져왔다. 바로 '나무 탈출' 이라는 보드게

www.acmicpc.net

1. 풀이방법

 

- 트리 구조를 이용한 DFS문제 입니다.

 

- 처음에 문제를 읽으면서 가장 고민이 되었던 건 리프노드는 구별이 가능한데 (간선이 1개뿐인 놈(루트제외))

 

- 리프노드에서 한칸 타고 부모로 올라갔을 때, 그다음 부모노드가 어떤 녀석인지를 판정을 어떻게 해야하나

 

- 고민을 많이하고, 결국 class로 노드를 만들어 포인터를 통해서 인접리스트 방식으로 트리를 구현해야하나 생각

 

- 했었는데, 너무 하기 귀찮아서 다시 문제를 읽어보았는데

 

- 사실 문제가 원하는 출력이 그렇게 복잡하지 않습니다. 이기냐, 지냐 만 출력하는 문제이므로

 

- 사실 각각의 리프노드들로 부터 루트노트(1) 까지 가는 간선의 수 (즉 높이) 들의 합이

 

- 홀수이냐, 아니면 짝수 이냐만 파악하면 문제의 정답을 출력할 수 있었습니다.

 

- 즉 ! 높이만 알면 되므로 리프노드 부터 탐색할 필요가 없이, 루트노드부터 dfs를 통해 리프노드까지 가면 됩니다!!!!

 

- 가장 고민하던 문제가 해결되었습니다. 그 다음 부터는 쉽습니다

 

- 그러므로 vector<int> tree[500001]을 통해 트리의 간선정보를 담고 

 

- bool visitnode[500001] 을통해 위에서 내려오는 부모노드는 방문체크를 하여 dfs탐색에서 제외 시켜줍니다.

 

 

 

 

 

2. 주의사항

 

- 리프노드는 연결된 간선이 무조건 하나!!!! 하지만 여기서 주의할 것은 간선이 하나가 될 수 있는 녀석이 하나 더

 

- 있습니다..>!   바로 루트노드는 간선이 하나만 연결될 수 있습니다. 그러므로 종료조건에 s!=1(루트노드)를 추가

 

- 해주었습니다.

 

 

 

 

3. 나의코드

#include<bits/stdc++.h>
using namespace std;

int N;
vector<int> tree[500001]; // 메모리때문에 인접행렬은 x 
bool visitnode[500001];
int totalheight = 0;
//간선이 하나만 존재하면 리프노드


void dfs(int s, int cnt) {
	if (tree[s].size() == 1 && s!=1) { //리프노드
		totalheight += cnt;
		return;
	}
	for (int i = 0; i < tree[s].size(); i++) {
		if (!visitnode[tree[s][i]]) {
			visitnode[tree[s][i]] = true;
			dfs(tree[s][i], cnt + 1);
			visitnode[tree[s][i]] = false;
		}
	}
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> N;
	for (int i = 0; i < N - 1; i++) {
		int tmp1, tmp2;
		cin >> tmp1 >> tmp2;
		tree[tmp1].push_back(tmp2);
		tree[tmp2].push_back(tmp1);
	}
	visitnode[1] = true;
	dfs(1, 0);
	if (totalheight % 2 == 1) cout << "Yes" << "\n";
	else { cout << "No" << "\n"; }
	
	return 0;
}

'알고리즘 문제풀이 > DFS와 BFS' 카테고리의 다른 글

백준 2638 [C++]  (0) 2021.01.24
백준 2251 [C++]  (0) 2021.01.19
백준 1600 [C++]  (0) 2021.01.19
백준 12851 [C++]  (0) 2021.01.18
백준 13913 [C++]  (0) 2021.01.18

www.acmicpc.net/problem/2251

 

2251번: 물통

각각 부피가 A, B, C(1≤A, B, C≤200) 리터인 세 개의 물통이 있다. 처음에는 앞의 두 물통은 비어 있고, 세 번째 물통은 가득(C 리터) 차 있다. 이제 어떤 물통에 들어있는 물을 다른 물통으로 쏟아 부

www.acmicpc.net

1. 풀이방법

 

- 물을 옮겨 담는 횟수에 제한이 없으므로 모든 경우의 수를 다 살펴보아야겠다고 생각하여

 

- dfs를 통해서 모든 경우의 수를 탐색했습니다.

 

- 종료조건을 걸어야 할까를 고민하다가 a,b,c 에 관한 3차원배열을 선언하여,

 

- 이미 체크를 했던 물의양 set이면 재귀를 통해 들어가지 않도록 하여 종료가 되게끔 구현하였습니다.

 

- 붓는 물의 양은 붓는 쪽의 물의 양과 부으려는 물통의 빈자리 중 더 적은 양 만큼을 부었습니다

 

 

2. 주의사항

 

- 종료조건 파악 및 구현

 

 

 

3. 나의코드

#include<bits/stdc++.h>
using namespace std;

int a, b, c;
bool already[201];
bool visitcheck[201][201][201];
vector<int> resultarr;

struct waterball {
	int ax, bx, cx;
};

void dfs(int ta, int tb, int tc) {
		visitcheck[ta][tb][tc] = true;
		if (ta==0) {
			if (already[tc] == false) {
				resultarr.push_back(tc);
				already[tc] = true;
			}
		}
		if (ta != 0 && tb != b) { //a에서 b로
			int tmpw = min((b - tb), (ta)); //b의 남은공간과 a의 물의 양중 작은 것
			if(visitcheck[ta-tmpw][tb+tmpw][tc]==false) dfs(ta - tmpw, tb + tmpw, tc);
		}
		if (ta != 0 && tc != c) { //a에서 c로
			int tmpw = min((c- tc), (ta)); //b의 남은공간과 a의 물의 양중 작은 것
			if (visitcheck[ta - tmpw][tb][tc+tmpw] == false) dfs(ta - tmpw, tb, tc+tmpw);
		}
		if (tb != 0 && tc != c) {//b에서 c로
			int tmpw = min((c - tc), (tb)); 
			if (visitcheck[ta][tb - tmpw][tc+tmpw] == false) dfs(ta , tb-tmpw, tc + tmpw);
		}
		if (tb != 0 && ta != a) {//b에서 a로
			int tmpw = min((a - ta), (tb)); 
			if (visitcheck[ta + tmpw][tb - tmpw][tc] == false)dfs(ta + tmpw, tb - tmpw, tc);
		}
		if (tc != 0 && ta != a) {//c에서 a로
			int tmpw = min((a - ta), (tc));
			if (visitcheck[ta + tmpw][tb][tc-tmpw] == false)dfs(ta + tmpw, tb , tc - tmpw);
		}
		if (tc != 0 && tb != b) {//c에서 b로
			int tmpw = min((b - tb), (tc));
			if (visitcheck[ta][tb + tmpw][tc-tmpw] == false)dfs(ta, tb + tmpw, tc - tmpw);
		}
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> a >> b >> c;
	dfs(0, 0, c);
	sort(resultarr.begin(), resultarr.end());
	for (int i = 0; i < resultarr.size(); i++) {
		cout << resultarr[i] << " ";
	}
	return 0;
}

'알고리즘 문제풀이 > DFS와 BFS' 카테고리의 다른 글

백준 2638 [C++]  (0) 2021.01.24
백준 15900 [C++]  (0) 2021.01.19
백준 1600 [C++]  (0) 2021.01.19
백준 12851 [C++]  (0) 2021.01.18
백준 13913 [C++]  (0) 2021.01.18

www.acmicpc.net/problem/1600

 

1600번: 말이 되고픈 원숭이

첫째 줄에 정수 K가 주어진다. 둘째 줄에 격자판의 가로길이 W, 세로길이 H가 주어진다. 그 다음 H줄에 걸쳐 W개의 숫자가 주어지는데, 0은 아무것도 없는 평지, 1은 장애물을 뜻한다. 장애물이 있

www.acmicpc.net

 

1. 풀이방법

 

- 약간은 어려워진 BFS인 것 같습니다.

 

- 체스의 나이트 처럼 이동할 수 있는 가능 횟수가 오직 K번 이므로, K번 + 나머지 횟수는 4방향탐색

 

- 을 통해 가야하는데 DFS로 구현을 할 경우 시간이 부족합니다.

 

- 그래서 BFS로 다시 짜는데, 핵심이라고 생각되는 것은 만약에 K번 중 한번을 사용하여 점프를 뛰고

 

- 바로 거기를 방문처리를 해버리면 4방향탐색을 통해 그쪽에 도착한 후 나중에 말 처럼 점프하는 사항을

 

- 고려할 수 가 없습니다.

 

- 그래서 평소 이용하는 visit 이차원 배열을 k의 수만큼 삼차원 배열로 만들어서

 

- k 중 몇번을 써서 왔는지를 확인하고 k번을 써서 i,j에 도착했을 경우 방문처리를 해줍니다.

 

- 만약 i,j로 왔는데 k를 한번도 사용하지 않고 왔다면 그 전에 i,j에 왔으나 k를 한번 써서 방문한 경우가 있어도

 

- 다시 큐로 들어가게끔 구현하였습니다.

 

 

 

2. 주의사항

 

- visit 처리

 

 

 

3. 나의코드

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

int k, w, h;
int chesspan[200][200];
bool visit[200][200][31]; //k는 0~30
int horsemovex[8] = { -1,-2,-2,-1,1,2,2,1 };
int horsemovey[8] = { -2,-1,1,2,2,1,-1,-2 };
int dx[4] = { 0,0,1,-1 }; //k번을 다 소모했을 경우
int dy[4] = { 1,-1,0,0 };
int s = 0;
int mincount = 99999999;
bool fail = false;
struct xyk {
	int x, y, kn,s;
};
queue<xyk> tmpq;

void inputs() { //1은 장애물
	cin >> k >> w >> h;
	for (int i = 0; i < h; i++) {
		for (int j = 0; j < w; j++) {
			cin >> chesspan[i][j];
		}
	}
}
bool boundcheck(int x, int y) {
	if (x >= 0 && x < h && y >= 0 && y < w) return true;
	else return false;
}
int bfs() {
	while (1) {
		int qsize = tmpq.size();
		while (qsize--) {
			if (tmpq.empty()) { fail = true; return 0; }
			int nextx = tmpq.front().x;
			int nexty = tmpq.front().y;
			int nextk = tmpq.front().kn;
			int nexts = tmpq.front().s;
			tmpq.pop();
			if (nextx == h - 1 && nexty == w - 1) { 
				return nexts; }
			if (nextk != 0) {
				for (int i = 0; i < 8; i++) {
					int tx = nextx+ horsemovex[i]; int ty =nexty+ horsemovey[i];
					if (boundcheck(tx, ty) && visit[tx][ty][nextk-1] == false && chesspan[tx][ty] != 1) {
						tmpq.push({ tx,ty,nextk - 1,nexts +1 });
						visit[tx][ty][nextk-1] = true;
					}
				}
			}
			for (int i = 0; i < 4; i++) {
				int tx2=nextx +dx[i]; int ty2 =nexty+ dy[i];
				if (boundcheck(tx2, ty2) && visit[tx2][ty2][nextk] == false && chesspan[tx2][ty2] != 1) {
					tmpq.push({ tx2,ty2,nextk,nexts +1 });
					visit[tx2][ty2][nextk] = true;
				}
			}
		}
	}
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	inputs();
	tmpq.push({ 0,0,k,0 });
	//출발점은 0,0 도착점은 h-1,w-1
	int r=bfs();
	if (fail == true) { cout << -1 << "\n"; }
	else cout <<r << "\n";


	return 0;
}

'알고리즘 문제풀이 > DFS와 BFS' 카테고리의 다른 글

백준 15900 [C++]  (0) 2021.01.19
백준 2251 [C++]  (0) 2021.01.19
백준 12851 [C++]  (0) 2021.01.18
백준 13913 [C++]  (0) 2021.01.18
백준 19238 [C++]  (0) 2021.01.17

www.acmicpc.net/problem/12851

 

12851번: 숨바꼭질 2

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때

www.acmicpc.net

1. 풀이방법 

 

- 숨바꼭질 4를 풀었다고 만만하게 덤볐다가 큰 코 다친 문제입니다..

 

- 문제를 많이 풀다보면 코드를 짤때 그 의미를 생각하지않고 항상 짜던데로 습관적으로 짜는 경향이 있는데,,,,

 

- 50퍼 정도에서 틀렸습니다 가 계속 나와서 질문검색에서 도움을 받았습니다.

 

-www.acmicpc.net/board/view/22749

 

글 읽기 - 12851번 숨바꼭질2 오답이 될만한 입력값

댓글을 작성하려면 로그인해야 합니다.

www.acmicpc.net

- 이분의 글을 보고 도움을 받았습니다.

 

- 제가 틀린 부분을 찾은 예시는

 

- 1 4

  입력시

  2

  2

(저는 1이 나왔었습니다)

- 였습니다.

 

-  1 -> 1+1 -> (1+1) * 2 (여기서 만약 2를 체크하면)

   1 -> 1*2 -> (1*2) * 2 (이 예시가 케이스로 들어가지 않음)

 

- 그래서 이 문제에서는 BFS를 돌때 큐에 넣을 때 VISIT을 체크하는 것이 아니라 큐에서 뺄 때 VISIT을 체크했습니다.

 

- 그외에는 K를 발견하면 그때의 큐를 끝까지 다 보는 방식으로 구현했습니다.

 

 

 

2. 주의사항

 

- 의미를 항상 생각하며 코드를 짜자!

 

 

 

3. 나의코드

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

int n, k;
int resultcount;
bool visit[100001];
queue<int> tmpq;
vector<int> tmpv;
int second = 1;
int nextn;
int qsize;
bool suc = false;
void checkrest() {
	while (qsize--) {
		nextn = tmpq.front(); tmpq.pop();
		if (nextn + 1 <= 100000 && nextn + 1 == k) resultcount++;
		if (nextn - 1 >= 0 && nextn - 1 == k) resultcount++;
		if (nextn * 2 <= 100000 && nextn * 2 == k) resultcount++;
	}
}

void bfs() {	
	while (1) {
		tmpv.clear();
		qsize = tmpq.size();
		while (qsize--) {
			nextn = tmpq.front();
			tmpq.pop();
			visit[nextn] = true;
			tmpv.push_back(nextn);
			
			//1증가
			if (nextn + 1 <= 100000 && visit[nextn + 1] == false) {
				tmpq.push(nextn + 1);
				if (nextn+1 == k) {
					resultcount++;
					checkrest();
					return; }
			}

			if (nextn - 1 >= 0 && visit[nextn - 1] == false) {
				tmpq.push(nextn - 1);
				if (nextn-1 == k) {
					resultcount++;
					checkrest();
					return; }
			}

			if (nextn * 2 <= 100000 && visit[2 * nextn] == false) {
				tmpq.push(nextn * 2);
				if (nextn*2 == k) {
					resultcount++;
					checkrest();
					return; }
			}
		}
		second++;
	}
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> n >> k;
	if (n >= k) {
		cout << n - k << "\n";
		cout << 1 << " ";
	}
	else {
		tmpq.push(n);
		visit[n] = true;
		bfs();
		cout << second << "\n" << resultcount << "\n";
	}
	return 0;
}

'알고리즘 문제풀이 > DFS와 BFS' 카테고리의 다른 글

백준 2251 [C++]  (0) 2021.01.19
백준 1600 [C++]  (0) 2021.01.19
백준 13913 [C++]  (0) 2021.01.18
백준 19238 [C++]  (0) 2021.01.17
백준 17142 [C++]  (0) 2021.01.17

www.acmicpc.net/problem/13913

 

13913번: 숨바꼭질 4

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

 

 

1. 풀이방법

 

- 걸리는 시간만 출력하라 했으면 정말 쉬웠을 텐데, 어떤식으로 경로도 출력 해야 합니다.

 

- 처음에는 출발점 1, 여기서 분화되는것이 3개 ( 배열:  0 | 1 2 3 )

 

- 그 다음 단계에서는 index 1,2,3 의 값(출발점에서 각각 3 개씩) ( 배열: 0 | 1 2 3 | 4 5 6 7 8 9 10 11 12 )

 

- 이런식으로 3의 제곱수로 분화된다는 것을 착안하여 k를 처음 발견한 위치의 index를 계산을 통해 앞쪽으로 이동

 

- 하면서 출력하였는데 시간이 너무 오래 걸립니다. (특히나 모든 경우의 수를 다 분화해서 가야하므로)

 

- 그래서 index계산을 통해서 가는 것을 포기하고 새로 bfs를 돌때 visit을 통해 방문한 지점은 다시 가지 않으므로

 

- 트리와 같은 느낌으로 어디서 왔는지 (부모가 누군지) 를 배열하나를 선언해서 넣어주면서 bfs를 돌고

 

- 나중에 k에서 시작해서 ---> 어디서왔는지를 쭉 탐색 ---> n을 발견하면 멈춤 이런식으로 구현하였습니다.

 

 

 

 

2. 주의사항

 

- 저 같은경우 출발점과 도착점은 무조건 출력해야 하는줄 알아서 

 

- 입력이 5 5 로 같으면 출력이 0 (시간) 5 5 (경로) 이렇게 인 것으로 착각 했으나

 

- n의 이동 경로이므로 5 하나만 출력해야 했습니다.

 

 

 

 

3. 나의코드

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;

int n, k;
queue<int> tmpq;
bool visit[100001];
int from[100001]; //어디서 온 놈인지르 표시해주자
vector<int> resultarr;

int second = 0;

int bfs() {
	while (1) {
		int qsize = tmpq.size();
		while (qsize--) {
			int nextn = tmpq.front();
			tmpq.pop();
			if (nextn == k) { return second; }
			//1증가
			if (nextn + 1 <= 100000&& visit[nextn + 1] == false) {
				resultarr.push_back(2 * nextn);
				tmpq.push(nextn+1);
				visit[nextn + 1] = true;
				from[nextn + 1] = nextn;
			}

			if (nextn - 1 >= 0 && visit[nextn - 1] == false ) {
				tmpq.push(nextn - 1);
				resultarr.push_back(nextn - 1);
				visit[nextn - 1] = true;
				from[nextn - 1] = nextn;
			}
			
			if (nextn * 2 <= 100000&& visit[2 * nextn] == false) {
				tmpq.push(nextn *2);
				resultarr.push_back(nextn *2);
				visit[2 * nextn] = true;
				from[2 * nextn]=nextn;
			}
		}
		second++;
	}
}
void findparent() {
	int tmpk = k;
	resultarr.clear();
	resultarr.push_back(tmpk);
	while (1) {
		if (from[tmpk] == n) { resultarr.push_back(n); break; }
		resultarr.push_back(from[tmpk]);
		tmpk = from[tmpk];
	}
	for (int i = resultarr.size() - 1; i >= 0; i--) {
		cout<<resultarr[i] << " ";
	}
}


int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> n >> k;
	int second = 0;
	if (n == k) { cout << 0 << "\n"; cout << n; return 0; }
	if (n > k) {
		cout << n-k<<"\n";
		cout << n << " ";
		for (int i = 1; i < (n - k); i++) {
			cout << n - i << " ";
		}
		cout << k << " ";
	}
	else {
		tmpq.push(n);
		visit[n] = true;
		cout << bfs() << "\n";
		findparent();
	}
	return 0;
}

 

'알고리즘 문제풀이 > DFS와 BFS' 카테고리의 다른 글

백준 1600 [C++]  (0) 2021.01.19
백준 12851 [C++]  (0) 2021.01.18
백준 19238 [C++]  (0) 2021.01.17
백준 17142 [C++]  (0) 2021.01.17
백준 16236 [C++]  (0) 2020.12.29

www.acmicpc.net/problem/19238

 

19238번: 스타트 택시

첫 줄에 N, M, 그리고 초기 연료의 양이 주어진다. (2 ≤ N ≤ 20, 1 ≤ M ≤ N2, 1 ≤ 초기 연료 ≤ 500,000) 연료는 무한히 많이 담을 수 있기 때문에, 초기 연료의 양을 넘어서 충전될 수도 있다. 다

www.acmicpc.net

1. 풀이방법

 

- BFS 활용문제 입니다.

 

- 문제의 조건이 좀 많고 , 주의하여야할 점이 좀 있는 문제였습니다.

 

- 일단 저 같은 경우 승객들의 출발지점은 모두 다르므로 승객의 도착점을 찾을 때는 

 

- 승객들 간의 분별이 가능한 출발점을 기준으로 찾았습니다 (그리고 그 찾은 승객의 INDEX를 통해서 도착점을 지정)

 

- 저같은 경우 첫 BFS 탐색을 통해 승객을 찾고 두번째 BFS를 통해 도착점을 찾았습니다.

 

- 승객을 찾아서 태우면 ground[i][j] =0  빈칸으로 바꿔주고 (한 칸에 두명 이상의 손님이 있는경우는 없으므로 상관 x)

 

- 도착점에 도착하면 그 도착점을 택시의 새로운 위치로 갱신하여 주었습니다.

 

 

 

 

2. 주의사항

 

- 도착점에서 손님을 내리고, 그곳에 손님이 있을경우 바로 태울 수 있다.

 

- 벽 때문에 도착하지 못하는 경우는 실패이다.

 

- 거리 > 행 > 열 순으로 승객을 특정한다.

 

- 승객을 찾으러 갈 때 연료가 부족하거나, 승객을 태우고 목적지로 가는 중 연료가 부족하면 실패이다.

 

- 그리고 "거리 > 행 > 열" 순으로 정렬을 하는 과정에서 실수가 있어 거의 한시간을 해맸는데..."

 

- 일단 2(즉, 승객) 을 찾으면 지금 현재 큐에 있는 승객들을 모두 벡터로 담아 소팅을 했는데

 

- 여기서 주석에서 보시다시피 while(!tmpq.empty()) 이런 실수를 했는데,

 

- 이럴경우 다음단계에 해당하는 녀석들도 큐에 들어가있는 상태 이므로 오류가 나옵니다.

 

- 보통 하나의 큐를 이용하여 bfs를 구현할 경우 한번의 반복문이 끝난후 그 큐의 size를 측정해서 하나의 단계로

 

- 취급하므로 이때도 while(ssize--)를 해야 했습니다.

 

 

 

3. 나의코드

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

int ground[21][21];
bool visit[21][21];
int n, m, fuel;
int texix, texiy;
int tmpx, tmpy;
//북서동남
int dx[4] = { -1,0,0,1 };
int dy[4] = { 0,-1,1,0 };
queue<pair<int, int>> tmpq;
bool fail = false;
int nextx, nexty;
int distances;
int ssize;
vector<pair<int,int>> tmpvector;

struct client {
	int sx, sy, ex, ey;
};
vector<client> clients;
bool compare(pair<int,int> &lhs, pair<int,int> &rhs) {
	if (lhs.first < rhs.first) return true;
	else if (lhs.first == rhs.first) {
		if (lhs.second < rhs.second) return true;
		else return false;
	}
	else return false;
}
void inputs() {
	cin >> n >> m>>fuel;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> ground[i][j];
		}
	}
	cin >> texix >> texiy;
	texix -= 1; texiy -= 1;
	for (int i = 0; i < m; i++) {
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		ground[x1-1][y1-1] = 2;
		clients.push_back({ x1-1,y1-1,x2-1,y2-1 });
	}
}
void qclear() {
	while (!tmpq.empty()) {
		tmpq.pop();
	}
}
void visitclear() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			visit[i][j] = false;
		}
	}
}
bool boundcheck(int x, int y) {
	if (x < 0 || x >= n || y < 0 || y >= n) return false;
	else return true;
}

void bfs() {
	distances = 0;
	bool checking = false;
	while (1) {
		if (tmpq.empty()) { fail = true; return; }
		 ssize = tmpq.size();
		while (ssize--) {
			 nextx = tmpq.front().first;
			 nexty = tmpq.front().second;
			 tmpq.pop();
			if (ground[nextx][nexty] == 2) { //손님을 찾으면 break;
				tmpvector.clear();
				tmpvector.push_back({ nextx,nexty });
				while (ssize--) { //  !!!!!! (!tmpq.empty()) 하면 틀림
					int ttx = tmpq.front().first;
					int tty = tmpq.front().second;
					tmpq.pop();
					if (ground[ttx][tty] == 2) {
						tmpvector.push_back({ ttx,tty });
					}
				}
				sort(tmpvector.begin(), tmpvector.end(), compare);
				nextx = tmpvector[0].first;
				nexty = tmpvector[0].second;
				checking = true; break;
			}
			for (int i = 0; i < 4; i++) {
				int tx = nextx + dx[i]; int ty = nexty + dy[i];
				if (boundcheck(tx, ty) && visit[tx][ty] == false && ground[tx][ty] != 1) {
					visit[tx][ty] = true;
					tmpq.push({ tx,ty });
				}
			}
		}
		if (checking == true) { break; }
		distances++;
	}
	fuel -= distances; //이동한만큼 연료소모
	if (fuel < 0) { fail = true; return; }
	ground[nextx][nexty] = 0; // 손님을 태웠슴
	int clientindex = -1;
	for (int i = 0; i < clients.size(); i++) {
		if (clients[i].sx == nextx && clients[i].sy == nexty) {
			clientindex = i; break; //손님의 목적지를 알기위해
		}
	}
	visitclear();
	qclear();
	tmpq.push({ nextx,nexty }); //출발지점
	ground[nextx][nexty] = 0; //손님을 태움
	visit[nextx][nexty] = true;

	distances = 0;
	checking = false;
	while (1) {
		if (tmpq.empty()) { fail = true; return; }
		ssize = tmpq.size();
		while (ssize--) {
			nextx = tmpq.front().first;
			nexty = tmpq.front().second;
			tmpq.pop();
			if (nextx==clients[clientindex].ex &&nexty==clients[clientindex].ey) { //손님을 찾으면 break;
				checking = true; break;
			}
			for (int i = 0; i < 4; i++) {
				int tx = nextx + dx[i]; int ty = nexty + dy[i];
				if (boundcheck(tx, ty) && visit[tx][ty] == false && ground[tx][ty] != 1) {
					visit[tx][ty] = true;
					tmpq.push({ tx,ty });
				}
			}
		}
		if (checking == true) {break; }
		distances++;
	}
	fuel -= distances;
	if (fuel < 0) {
		fail = true; return;
	}
	texix = nextx; texiy = nexty; //택시 위치 변경
	fuel += (2 * distances);
}
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	inputs();
	for (int i = 0; i < m; i++) {
		qclear();
		visitclear();
		tmpq.push({ texix,texiy });
		visit[texix][texiy] = true;
		bfs();//손님찾자
		if (fail == true) { cout << -1 << "\n"; return 0; }
	}

	cout << fuel << "\n";
	return 0;
}

'알고리즘 문제풀이 > DFS와 BFS' 카테고리의 다른 글

백준 12851 [C++]  (0) 2021.01.18
백준 13913 [C++]  (0) 2021.01.18
백준 17142 [C++]  (0) 2021.01.17
백준 16236 [C++]  (0) 2020.12.29
백준 2644 [C++]  (0) 2020.12.22

www.acmicpc.net/problem/17142

 

17142번: 연구소 3

인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고

www.acmicpc.net

1. 풀이방법

 

- 브루트포스(경우의 수 모두 구하기) + BFS탐색 (바이러스 전파) 문제입니다.

 

- 전 빈칸의 개수를 입력받을 때 미리 구해놓고 종료조건으로 활용하였습니다.

 

 

 

2. 주의사항

 

- 종료조건을 큐 가 비었을 때만 걸면 안됩니다. 빈칸은 없지만 비활성바이러스만 남아있을경우 BFS를 또 돌게되어

 

- 출력이 달라집니다.

 

- 그래서 종료조건에 빈칸이 모두 없어졌을 때를 추가로 걸어주었습니다.

 

- 제한시간이 0.25초 인데 만약 모두 전이되었는지 체크를 할때 이중탐색문을 사용할 경우 시간초과가 뜰 수 있습니다.

 

 

 

3. 나의코드

 

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

int n, m;
int vground[51][51];
bool visit[51][51];
int minresult = 9999;
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
vector<pair<int, int>> canvirus;
vector<pair<int, int>> tmpvirus;
queue<pair<int, int>> tmpq;
bool suc = false;
int totalzero = 0;
int tmpzero = 0;


void inputs() {
	cin >> n >> m;
	for (int i = 0; i < n; i++) { //0은 빈칸, 1은 벽, 2는 바이러스 가능위치
		for (int j = 0; j < n; j++) {
			cin >> vground[i][j];
			if (vground[i][j] == 2) {
				canvirus.push_back({ i,j });
			}
			if (vground[i][j] == 0) {
				totalzero++;
			}
		}
	}
}
void qclear() {
	while (!tmpq.empty()) {
		tmpq.pop();
	}
}
void vtoq() {
	for (int i = 0; i < tmpvirus.size(); i++) {
		tmpq.push(tmpvirus[i]);
		visit[tmpvirus[i].first][tmpvirus[i].second] = true;
	}
}
void visitclear() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			visit[i][j] = false;
		}
	}
}
bool boundcheck(int x, int y) {
	if (x < 0 || x >= n || y < 0 || y >= n) return false;
	else return true;
}

void bfs() {
	int second=0;
	while (1) {
		if (tmpzero==0|| tmpq.empty()) break;
		int qsize = tmpq.size();
		while (qsize--) {
			int nextx = tmpq.front().first;
			int nexty = tmpq.front().second;
			tmpq.pop();
			for (int i = 0; i < 4; i++) {
				int tx = nextx + dx[i]; int ty = nexty + dy[i];
				if (boundcheck(tx, ty) && visit[tx][ty] == false && vground[tx][ty]!=1) {
					tmpq.push({ tx,ty });
					visit[tx][ty] = true;
					if (vground[tx][ty] == 0) tmpzero--;
				}
			}
		}
		second++;
	}
	if (tmpzero==0) {
		suc = true;
		if (second < minresult) minresult = second;
	}

}

void makecase(int index,int cnt) {
	if (cnt == m) {
		visitclear(); //방문배열 초기화
		qclear(); //큐 를 먼저 싹 빼줌 초기화
		vtoq(); //벡터에서 큐로 옮기기 (방문체크도)
		tmpzero = totalzero; // 바이러스가 모두 전파되었는지확인
		bfs();
		return;
	}
	for (int i = index; i < canvirus.size(); i++) {
		tmpvirus.push_back(canvirus[i]);
		makecase(i + 1, cnt + 1);
		tmpvirus.pop_back();
	}

}



int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	inputs();
	makecase(0,0);
	if (suc == true) cout << minresult << "\n";
	else cout << -1 << "\n";
	return 0;
}

'알고리즘 문제풀이 > DFS와 BFS' 카테고리의 다른 글

백준 13913 [C++]  (0) 2021.01.18
백준 19238 [C++]  (0) 2021.01.17
백준 16236 [C++]  (0) 2020.12.29
백준 2644 [C++]  (0) 2020.12.22
백준 7569 [C++]  (1) 2020.12.20

+ Recent posts