Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[위상 정렬] 6월 7일 #17

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions #19 0607_위상_정렬/BOJ_14907_sample.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <iostream>
#include <vector>
#include <queue>

using namespace std;
const int SIZE = 26;

vector<string> splitInput(string input) { //입력 문자열 분리
vector<string> result; //작업 번호, 작업 일수, 전에 해야하는 작업 목록 순서로 저장
string tmp;
input += " "; //마지막 문자열 분리를 위해 공백 추가
for (int i = 0; i < input.length(); i++) {
if (input[i] == ' ') {
result.push_back(tmp);
tmp = "";
continue;
}
tmp += input[i];
}
return result;
}

//위상정렬 + DP
int topologicalSort(vector<int> &days, vector<int> &indegree, vector<vector<int>> &graph) {
queue<int> q;
vector<int> dp(SIZE, 0); //현재 작업 하기까지 걸린 시간
int ans = 0;

for (int i = 0; i < SIZE; i++) {
dp[i] = days[i]; //dp 배열 초기화
if (days[i] && !indegree[i]) {
q.push(i);
}
}
while (!q.empty()) {
int node = q.front();
q.pop();

ans = max(ans, dp[node]); //정답 갱신 (마지막 정점이 여러 개일 경우, 가장 긴 시간을 선택해야 하기 때문)
for (int i = 0; i < graph[node].size(); i++) {
int next_node = graph[node][i];
indegree[next_node]--;
if (!indegree[next_node]) {
q.push(next_node);
}
//다음 정점의 최소 시간 계산 -> 이어진 전 정점 중 가장 긴 작업 일수를 가진 정점을 선택
dp[next_node] = max(dp[next_node], dp[node] + days[next_node]);
}
}
return ans;
}

int main() {
vector<int> indegree(SIZE, 0);
vector<vector<int>> graph(SIZE, vector<int>(0));
vector<int> days(SIZE, 0);
string input;

//입력
while (getline(cin, input)) {
vector<string> list = splitInput(input);
int work = list[0][0] - 'A'; //작업 번호
days[work] = stoi(list[1]); //해당 작업 일수
if (list.size() == 2) { //그 전에 해야 하는 작업이 없다면
continue;
}
string prev = list[2]; //그 전에 해야 하는 작업
indegree[work] = prev.length();
for (int i = 0; i < prev.length(); i++) {
graph[prev[i] - 'A'].push_back(work);
}
}

//연산 & 출력
cout << topologicalSort(days, indegree, graph);
return 0;
}
62 changes: 62 additions & 0 deletions #19 0607_위상_정렬/BOJ_1516_sample.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

//위상정렬 + DP
vector<int> topologicalSort(int n, vector<int> &t, vector<int> &indegree, vector<vector<int>> &graph) {
queue<int> q;
vector<int> dp(n + 1, 0);

for (int i = 1; i <= n; i++) {
dp[i] = t[i];
if (!indegree[i]) {
q.push(i);
}
}
while (!q.empty()) {
int node = q.front();
q.pop();

for (int i = 0; i < graph[node].size(); i++) {
int next_node = graph[node][i];
dp[next_node] = max(dp[next_node], dp[node] + t[next_node]);

indegree[next_node]--;
if (!indegree[next_node]) {
q.push(next_node);
}
}
}
return dp;
}

int main() {
int n, input;

//입력
cin >> n;
vector<int> t(n + 1, 0); //건물을 짓는데 걸리는 시간
vector<int> indegree(n + 1, 0);
vector<vector<int>> graph(n + 1, vector<int>(0));
for (int i = 1; i <= n; i++) {
cin >> t[i];
while (cin >> input) {
if (input == -1) {
break;
}
graph[input].push_back(i);
indegree[i]++;
}
}

//연산
vector<int> ans = topologicalSort(n, t, indegree, graph);

//출력
for (int i = 1; i <= n; i++) {
cout << ans[i] << '\n';
}
return 0;
}
44 changes: 44 additions & 0 deletions #19 0607_위상_정렬/BOJ_1744_sample.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int tieNumber(vector<int> &arr) {
int total = 0;
int size = arr.size();
for (int i = 0; i < size - 1; i += 2) {
total += arr[i] * arr[i + 1];
}
//하나 남은 수 더해줌
if (size % 2) {
total += arr[size - 1];
}
return total;
}

int main() {
int n, x, cnt1 = 0;

//입력
cin >> n;
vector<int> arr_pos, arr_neg;
while (n--) {
cin >> x;
if (x > 1) {
arr_pos.push_back(x);
} else if (x < 1) {
arr_neg.push_back(x);
} else {
cnt1++;
}
}

//절댓값이 큰 순으로 정렬
sort(arr_pos.begin(), arr_pos.end(), greater<>());
sort(arr_neg.begin(), arr_neg.end());

//연산 & 출력
cout << cnt1 + tieNumber(arr_pos) + tieNumber(arr_neg);
return 0;
}
60 changes: 60 additions & 0 deletions #19 0607_위상_정렬/BOJ_2637_sample.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <iostream>
#include <vector>
#include <queue>

using namespace std;
typedef pair<int, int> ci;

vector<int> bfs(int n, vector<vector<ci>> &graph) {
queue<int> q;
vector<int> cnt(n + 1, 0); //큐에 있는 부품 번호에 따른 개수 저장 + 방문체크
vector<int> ans(n + 1, 0); //기본 부품 개수 저장

//시작 정점 초기화
q.push(n);
cnt[n] = 1;

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

//리프노드(기본부품)인 경우
if (graph[x].empty()) {
ans[x] += cnt[x];
}
//중간부품인 경우
for (int i = 0; i < graph[x].size(); i++) {
int y = graph[x][i].first;
int k = graph[x][i].second;
if (!cnt[y]) {
q.push(y);
}
cnt[y] += k * cnt[x];
}
cnt[x] = 0; //처리가 끝나면 0으로 리셋
}
return ans;
}

int main() {
int n, m, x, y, k;

//입력
cin >> n >> m;
vector<vector<ci>> graph(n + 1, vector<ci>(0));
while (m--) {
cin >> x >> y >> k;
graph[x].push_back({y, k});
}

//연산
vector<int> result = bfs(n, graph);

//출력
for (int i = 1; i <= n; i++) {
if (result[i]) {
cout << i << ' ' << result[i] << '\n';
}
}
return 0;
}
130 changes: 130 additions & 0 deletions #19 0607_위상_정렬/PG__sample.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;
typedef pair<int, int> ci;
const int SIZE = 4;

int dr[4] = {-1, 1, 0, 0};
int dc[4] = {0, 0, -1, 1};

//컨트롤로 이동하는 좌표를 리턴하는 함수
ci ctrl(int row, int col, int dir, vector<vector<int>> &tmp) {
while (true) {
row += dr[dir];
col += dc[dir];
if (row < 0 || row >= SIZE || col < 0 || col >= SIZE) { //해당 방향에 카드가 하나도 없다면 그 방향의 가장 마지막 칸으로 이동
return make_pair(row - dr[dir], col - dc[dir]);
}
if (tmp[row][col] != 0) { //누른 키 방향에 있는 가장 가까운 카드
return make_pair(row, col);
}
}
}

//현재 커서에서 목표 카드로 이동하는 가장 적은 비용을 리턴하는 함수
int bfs(int r1, int c1, int r2, int c2, vector<vector<int>> &tmp) {
vector<vector<int>> visited(SIZE, vector<int>(SIZE, 0));
queue<ci> q;
visited[r1][c1] = 1; //반드시 엔터를 누르게 될 것. 엔터를 미리 눌렀다 가정하고 1로 표시
q.push({r1, c1});

while (!q.empty()) {
int row = q.front().first;
int col = q.front().second;
int dist = visited[row][col];
q.pop();

if (row == r2 && col == c2) { //목표 카드에 도달했다면
return dist;
}
for (int i = 0; i < 4; i++) { //컨트롤 입력 이동
pair<int, int> np = ctrl(row, col, i, tmp);
if (visited[np.first][np.second]) {
continue;
}
visited[np.first][np.second] = dist + 1;
q.push(np);
}

for (int i = 0; i < 4; i++) { //방향키 입력 이동
int nr = row + dr[i], nc = col + dc[i];
if (nr < 0 || nr >= SIZE || nc < 0 || nc >= SIZE || visited[nr][nc]) {
continue;
}
visited[nr][nc] = dist + 1;
q.push({nr, nc});
}
}
return -1; //목표 카드에 도달하지 못함 (실제로는 일어나지 않는 일)
}

//조합에 대해 카드를 매칭하는 함수
int matchCard(int bit, int num, int r, int c, int answer, vector<int> &seq, vector<vector<ci>> &cards,
vector<vector<int>> tmp) {
int ans = 0;
for (int i = 0; i < num; i++) {
int cur = seq[i]; //이번에 매칭할 캐릭터
int now = 0; //해당 캐릭터의 0번째 카드부터 선택한다고 가정
if (bit & (1 << i)) { //만약 해당 위치의 비트가 1을 표시했다면 1번째 카드부터 선택
now = 1;
}
for (int j = 0; j < 2; j++) {
int nr = cards[cur][now].first, nc = cards[cur][now].second; //이번에 매칭할 카드 위치
ans += bfs(r, c, nr, nc, tmp); //현재 커서에서 목표 카드까지 이동하는 비용
//기존 최솟값보다 큰 경우 -> 더 이상의 탐색 불필요
if (ans >= answer) {
return answer;
}
//카드 삭제 + 커서 이동
tmp[nr][nc] = 0;
r = nr;
c = nc;
now = 1 - now; //다음에 매칭할 카드 인덱스
}
}
return ans;
}

//존재하는 모든 카드의 위치를 리턴하는 함수
vector<vector<ci>> findCard(vector<vector<int>> &board) {
vector<vector<ci>> card_pos(7, vector<ci>(0)); //최대 카드 수
int cnt = 0;
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
cnt = max(cnt, board[i][j]);
if (board[i][j]) { //카드라면 위치 저장
card_pos[board[i][j]].push_back({i, j});
}
}
}
card_pos.resize(cnt + 1); //실제 존재하는 카드의 수만큼 크기 조절
return card_pos;
}

int solution(vector<vector<int>> board, int r, int c) {
int answer = 1e9;
vector<vector<ci>> cards = findCard(board); //존재하는 모든 카드의 위치
int card_cnt = cards.size() - 1; //카드의 개수

vector<int> seq(card_cnt); //순열을 위한 배열
for (int i = 0; i < card_cnt; i++) {
seq[i] = i + 1;
}
do { //가능한 모든 카드 순서에 대해
for (int bit = 0; bit < (1 << card_cnt); bit++) { //0, 1번째 카드 중 어떤 카드를 먼저 뒤집을지 결정
answer = min(answer, matchCard(bit, card_cnt, r, c, answer, seq, cards, board));
}
} while (next_permutation(seq.begin(), seq.end()));
return answer;
}

int main() {
vector<vector<int>> board = {{1, 0, 0, 3},
{2, 0, 0, 0},
{0, 0, 0, 2},
{3, 0, 1, 0}};
cout << solution(board, 1, 0);
}