충남대학교 컴퓨터공학과 이영석 교수님의 "알고리즘" 강의 실습 내용입니다.

  • 실습 문제들의 코드 위주로 구성되어 있습니다.

문제 1: DFS, BFS 구현하기

#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <queue>
#include <vector>
 
using namespace std;
 
// 방문한 노드를 저장할 배열
int visitedDFS[13] = {};
int visitedBFS[13] = {};
// 방문 결과를 저장할 배열
vector<string> vecDFS;
vector<string> vecBFS;
 
void dfs(map<string, vector<string>> mMap, string cur) {
	// 방분한 노드를 저장
	vecDFS.push_back(cur);
	// 인접노드 배열을 저장
	auto els = mMap[cur];
	// 인접노드를 뒤에서부터 탐색
	for(auto it = els.rbegin(); it != els.rend(); it++) {
		// 만약 방문하지 않은 노드일때
		if(visitedDFS[(*it)[0] - 'A'] != 1) {
			// 방문함으로 바꿔주고
			visitedDFS[(*it)[0] - 'A'] = 1;
			// 다음노드를 방문
			dfs(mMap, *it);
		}
	}
}
 
void bfs(map<string, vector<string>> mMap, string start) {
	// 큐를 생성하고 첫번째 노드를 큐에 넣어줌
	queue<string> q;
	q.push(start);
	visitedBFS[start[0] - 'A'] = 1;
	while(!q.empty()) {
		// 큐의 헤드를 pop하여 현재 노드를 얻어옴
		string h = q.front();
		q.pop();
		// 현재 노드를 방문 목록에 추가함
		vecBFS.push_back(h);
		// 현재 노드와 인접 노드를 순회함
		for(const auto& el : mMap[h]) {
			// 만약 방문하지 않은 노드일때
			if(visitedBFS[el[0] - 'A'] != 1) {
				// 방문함으로 바꿔주고
				visitedBFS[el[0] - 'A'] = 1;
				// 해당 노드를 큐에 넣어줌
				q.push(el);
			}
		}
	}
}
 
int main() {
	string chStart;
	cin >> chStart;
	map<string, vector<string>> mMap;
	
	// input을 받음
	for(int i = 0; i < 13; i++) {
		string line;
		getline(cin, line);
		stringstream ss(line);
		string key, val;
		getline(ss, key, ' ');
		mMap[key] = {};
		while(getline(ss, val, ' ')) {
			mMap[key].push_back(val);
		}
	}
	
	// BFS로 노드들을 순회하여 그의 결과를 저장함
	bfs(mMap, chStart);
 
	// 첫번째 노드를 방문했음으로 바꿔주고 DFS로 노드들을 순회하여 그의 결과를 저장함
	visitedDFS[chStart[0] - 'A'] = 1;
	dfs(mMap, chStart);
	
	// BFS에 대해 방문한 노드들을 출력함
	for(int i = 0; i < 12; i++) {
		cout << vecBFS[i] << ' ';
	}
	cout << vecBFS[12] << endl;
	
	// DFS에 대해 방문한 노드들을 출력함
	for(int i = 0; i < 12; i++) {
		cout << vecDFS[i] << ' ';
	}
	cout << vecDFS[12] << endl;
 
	
	return 0;
}

문제 2: 후플푸프의 컵

/**
 * CNU week6
 * 
 * Hufflepuff's cup
 * 
 * DFS
 * 
 * refs: getline + stoi
 */
 
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
 
using namespace std;
 
// 트로피들의 관계를 저장하는 2차원 배열
vector<vector<int>> mMap;
// 방문체크를 위한 배열
bool* visited;
// 트로피의 갯수
int nCups;
 
bool fnVisit(int cur) {
	// 만약 마지막 트로피에 도달하면 참을 반환하고 종료
	if(cur == nCups - 1) {
		return true;
	}
	// 현재의 노드를 방문했음으로 변경함
	visited[cur] = true;
	// 트로피에 담긴 쪽지들을 순회함
	for(const auto& nTicket : mMap[cur]) {
		// 만약 방문하지 않은 트로피가 쪽지에 있으면
		if(!visited[nTicket]) {
			// 해당 트로피를 방문하고 만약 제일 끝까지 도달하였으면 바로 참을 반환하고 종료
			if(fnVisit(nTicket)) {
				return true;
			}
		}
	}
	// 만약 인접한 어느 트로피도 마지막까지 도달하지 못했으면 거짓을 반환하고 종료
	return false;
}
 
int main() {
	// input을 받아옴
	cin >> nCups;
	visited = new bool[nCups];
	string strIn, chIn;
	mMap.reserve(nCups);
	cin.ignore();
	for(int i = 0; i < nCups; i++) {
		visited[i] = false;
		getline(cin, strIn);	
		stringstream ss(strIn);
		vector<int> vecTemp;
		while(getline(ss, chIn, ' ')) {
			if(chIn.size() > 0) {
				vecTemp.push_back(stoi(chIn));
			}
		}
		mMap.push_back(vecTemp);
	}
 
	// 0번 트로피부터 방문하여
	//	 마지막 트로피까지 도달하였으면 True를 출력하고
	//	 도달하지 못하였으면 False를 출력함
	if(fnVisit(0)) {
		cout << "True" << endl;
	} else {
		cout << "False" << endl;
	}
 
	delete visited;
	return 0;
}

문제 3: 독점 무역로 구하기

#include <iostream>
#include <vector>
#include <array>
#include <queue>
#include <algorithm>
#include <set>
 
using namespace std;
 
int nCities, nRoads;
 
bool fnVisit(const vector<vector<int>>& vecMap) {
	// 방문체크를 위한 배열 선언
	vector<bool> visited(nCities);
	// 첫번째 노드를 방문함드로 명시
	visited[0] = true;
	// 큐를 생성하고 첫번째 노드를 삽입함
	queue<int> q;
	q.push(0);
	// 큐가 비어있지 않을때까지 반복
	while(!q.empty()) {
		// 큐의 헤드를 받아오고 pop함
		int h = q.front();
		q.pop();
		// 큐와 인접한 노드들을 순회함
		for(const auto& n : vecMap[h]) {
			// 만약 방문하지 않은 인접 노드가 있을때
			if(!visited[n]) {
				// 방문함으로 변경하고
				visited[n] = true;
				// 해당 노드를 큐에 넣어줌
				q.push(n);
			}
		}
	}
	// 모든 노드를 방문하였는지 체크하여
	//	 방문하지 않은 노드가 있으면 단절되었다는 뜻이므로 
	//	 false를 반환하고 종료
	for(const auto& el : visited) {
		if(!el) {
			return false;
		}
	}
	// 모든 노드를 방문하였으면 true를 반환하고 종료
	return true;
}
 
// 도로를 이용해 노드들간의 양방향 그래프를 만들어주는 함수
vector<vector<int>> fnGetConn(const set<array<int, 2>>& vecRoads) {
	// 양방향 그래프를 저장할 배열
	vector<vector<int>> vecMap(nCities);
	// 도로들을 하나씩 순회함
	for(const auto& road : vecRoads) {
		// 양방향 그래프이므로 서로서로 연결되어있다고 명시
		vecMap[road[0]].push_back(road[1]);
		vecMap[road[1]].push_back(road[0]);
	}
	// 양방향 그래프를 반환
	return vecMap;
}
 
int main() {
	// 도로들에 대한 input을 입력받음
	cin >> nCities >> nRoads;
	set<array<int, 2>> vecRoads;
	for(int i = 0; i < nRoads; i++) {
		array<int, 2> road;
		cin >> road[0] >> road[1];
		sort(road.begin(), road.end());
		vecRoads.insert(road);
	}
 
	// 독점 무역로에 대한 집합
	set<array<int, 2>> vecRes;
 
	// 도로들을 하나씩 순회하며
	for(const auto& road : vecRoads) {
		// 도로 목록에 대한 복사본을 생성하고 도로 하나를 제거함
		auto deleted = vecRoads;
		deleted.erase(find(deleted.begin(), deleted.end(), road));
		// 제거된 도로 목록을 이용해 양방향 그래프를 생성
		auto delConn = fnGetConn(deleted);
		// 각 도시들을 순회하여 만약 단절된 도시가 있으면 제거한 도로를 결과에 넣어줌
		if(!fnVisit(delConn)) {
			vecRes.insert(road);
		}
	}
 
	// 독점 무역로 집합을 출력함
	for(const auto& road : vecRes) {
		cout << road[0] << ' ' << road[1] << endl;
	}
 
	return 0;
}