IT 프로그래밍/알고리즘
[알고리즘] Greedy Method
기술1
2025. 6. 25. 16:22
// 통합 그래프 알고리즘 구현 파일
// 포함 알고리즘: DFS, TopoSort, SCC(Kosaraju), Kruskal, Prim, WidestPath, EFTF 구간 스케줄링, Box Stacking
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <fstream>
#include <algorithm>
#include <tuple>
using namespace std;
// ========================== 공통 변수 ==========================
int V, E;
vector<vector<pair<int, int>>> adj; // 가중치 포함 그래프
vector<vector<int>> graph, rev_graph;
vector<bool> visited;
vector<int> parent;
// ========================== DFS ==========================
void dfs_util(int u) {
visited[u] = true;
cout << u << " ";
for (auto [v, _] : adj[u]) if (!visited[v]) dfs_util(v);
}
void DFS() {
visited.assign(V, false);
cout << "DFS 순회: "; dfs_util(0); cout << endl;
}
// ========================== Topological Sort (DAG 전용) ==========================
vector<int> topo_result;
void topo_dfs(int u) {
visited[u] = true;
for (auto [v, _] : adj[u]) if (!visited[v]) topo_dfs(v);
topo_result.push_back(u);
}
void TopologicalSort() {
visited.assign(V, false); topo_result.clear();
for (int i = 0; i < V; i++) if (!visited[i]) topo_dfs(i);
reverse(topo_result.begin(), topo_result.end());
cout << "Topological Sort 결과: ";
for (int x : topo_result) cout << x << " ";
cout << endl;
}
// ========================== SCC (Kosaraju) ==========================
stack<int> finish_order;
vector<vector<int>> SCCs;
void dfs1(int u) {
visited[u] = true;
for (int v : graph[u]) if (!visited[v]) dfs1(v);
finish_order.push(u);
}
void dfs2(int u, vector<int>& comp) {
visited[u] = true; comp.push_back(u);
for (int v : rev_graph[u]) if (!visited[v]) dfs2(v, comp);
}
void SCC_Kosaraju() {
visited.assign(V, false);
for (int i = 0; i < V; ++i) if (!visited[i]) dfs1(i);
visited.assign(V, false);
while (!finish_order.empty()) {
int u = finish_order.top(); finish_order.pop();
if (!visited[u]) {
vector<int> comp; dfs2(u, comp);
SCCs.push_back(comp);
}
}
cout << "총 SCC 개수: " << SCCs.size() << endl;
for (size_t i = 0; i < SCCs.size(); ++i) {
cout << "SCC " << i + 1 << ": ";
for (int v : SCCs[i]) cout << v << " "; cout << endl;
}
}
// ========================== Kruskal MST ==========================
struct Edge { int u, v, w; };
vector<Edge> edges;
int find(int u) { return parent[u] == u ? u : parent[u] = find(parent[u]); }
bool unite(int u, int v) {
u = find(u); v = find(v);
if (u == v) return false;
parent[v] = u; return true;
}
void Kruskal() {
parent.resize(V); for (int i = 0; i < V; ++i) parent[i] = i;
sort(edges.begin(), edges.end(), [](Edge a, Edge b) { return a.w < b.w; });
int mst_cost = 0;
cout << "Kruskal MST 간선: \n";
for (Edge e : edges) {
if (unite(e.u, e.v)) {
cout << e.u << " - " << e.v << " : " << e.w << endl;
mst_cost += e.w;
}
}
cout << "MST 총 비용: " << mst_cost << endl;
}
// ========================== Prim MST ==========================
void Prim() {
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
vector<int> dist(V, 1e9); dist[0] = 0;
vector<bool> inMST(V, false);
pq.push({0, 0}); int mst_cost = 0;
while (!pq.empty()) {
auto [d, u] = pq.top(); pq.pop();
if (inMST[u]) continue;
inMST[u] = true; mst_cost += d;
for (auto [v, w] : adj[u]) if (!inMST[v] && w < dist[v]) {
dist[v] = w; pq.push({w, v});
}
}
cout << "Prim MST 총 비용: " << mst_cost << endl;
}
// ========================== Widest Path ==========================
void WidestPath(int src) {
vector<int> width(V, 0); width[src] = 1e9;
priority_queue<pair<int, int>> pq; pq.push({1e9, src});
while (!pq.empty()) {
auto [w, u] = pq.top(); pq.pop();
for (auto [v, cost] : adj[u]) {
int min_width = min(w, cost);
if (min_width > width[v]) {
width[v] = min_width;
pq.push({width[v], v});
}
}
}
cout << "Widest path 값: \n";
for (int i = 0; i < V; ++i)
cout << "0 → " << i << ": " << width[i] << endl;
}
// ========================== Earliest Finish Time First ==========================
struct Interval { int id, start, end; };
bool compatible(const Interval& a, const Interval& b) { return a.end <= b.start; }
void IntervalScheduling_EFTF(const string& fname) {
ifstream in(fname);
int n; in >> n;
vector<Interval> jobs(n);
for (int i = 0; i < n; ++i) in >> jobs[i].start >> jobs[i].end, jobs[i].id = i;
sort(jobs.begin(), jobs.end(), [](Interval a, Interval b) { return a.end < b.end; });
vector<int> selected;
int last_end = -1;
for (auto j : jobs) if (j.start >= last_end) {
selected.push_back(j.id); last_end = j.end;
}
cout << "EFTF 선택된 작업 ID: "; for (int id : selected) cout << id << " "; cout << endl;
}
// ========================== 입력 및 실행 ==========================
void loadGraph(const string& fname) {
ifstream in(fname);
if (!in) { cerr << "파일 열기 실패!\n"; exit(1); }
in >> V >> E;
adj.assign(V, {});
graph.assign(V, {}); rev_graph.assign(V, {}); edges.clear();
for (int i = 0; i < E; ++i) {
int u, v, w; in >> u >> v >> w;
adj[u].push_back({v, w});
graph[u].push_back(v);
rev_graph[v].push_back(u);
edges.push_back({u, v, w});
}
in.close();
}
int main() {
cout << "그래프 입력 파일명 (예: input.txt): ";
string fname; cin >> fname;
loadGraph(fname);
cout << "\n1: DFS\n2: Topological Sort\n3: SCC (Kosaraju)\n4: Kruskal MST\n5: Prim MST\n6: Widest Path (0기준)\n7: Interval Scheduling (EFTF)\n선택: ";
int op; cin >> op;
if (op == 1) DFS();
else if (op == 2) TopologicalSort();
else if (op == 3) SCC_Kosaraju();
else if (op == 4) Kruskal();
else if (op == 5) Prim();
else if (op == 6) WidestPath(0);
else if (op == 7) IntervalScheduling_EFTF("intervals.txt");
else cout << "잘못된 입력\n";
return 0;
}
/*
📘 사용법:
input.txt: 정점 수, 간선 수, u v w
intervals.txt: N, 각 작업의 시작/종료 시간
예시:
intervals.txt
5
1 4
2 5
3 6
5 7
6 9
컴파일: g++ -o graph graph.cpp
실행: ./graph
*/