티스토리 뷰
1. 문제 링크
https://www.acmicpc.net/problem/2316
2316번: 도시 왕복하기 2
N개의 도시가 P개의 양방향 길로 연결되어 있다. 이석원은 1번 도시와 2번 도시 사이를 오가며 워해머를 한다. 성실한 이석원은 두 도시 사이를 최대한 많이 왔다 갔다 하려 하는데, 이때 한 번 방문했던 도시(1, 2번 도시 제외)를 두 번 이상 방문하지 않으려 한다. 한 번 1번 도시와 2번 도시 사이를 오갈 때, 반드시 한 개 이상의 도시를 중간에 거쳐야 한다. 입력에는 1번 도시와 2번 도시를 연결하는 길은 없다. 도시의 번호는 1번부터 N번까지이다
www.acmicpc.net
2. 문제 개요
N개의 도시가 P개의 양방향 길로 연결되어 있다.
1 --- 2 번 도시를 오갈 때, 반드시 1개 이상의 도시를 중간에 거쳐야 한다. 한번 방문한 도시는 두 번 이상 방문하지 않으려 한다. 입력에는 1번 도시와 2번 도시를 연결하는 길은 없다.
왔다 갔다 할 수 있는 최대 횟수를 구하기.
3. 문제 힌트
Network flow문제이다.
한 도시를 두 번 이상 방문하지 않으려고 할 때 어떻게 하면 구분할 수 있을까?
-정점 분할
하나의 마을을 2개의 정점으로 분할시켜보자.

4. 문제 풀이
네트워크 플로우 문제는 디자인하는 능력이 절반이상인것 같다.
한 마을을 2번 이상 거치지 않도록 하기위해 마을을 2개의 정점으로 분리하고 용량 1의 간선으로 연결한다.
그리고 마을 사이에는 out -> in으로 가는 간선과 out -> in으로 가는 간선을 다 연결해주고, 용량 1로 설정해준다.
포드 풀커슨 알고리즘을 사용하여 src에서 dest까지 실행한다.
5. 코드
#include <cstdio> #include <vector> #include <queue> #include <algorithm> using namespace std; const int out = 400; const int src = 401, dest = 2; //house, [in,out] vector<int>v[801]; //index로부터 출발하는 간선 int c[801][801], f[801][801]; int n, m, ans; void edmondkarp() { while (1) { int p[801]; fill(p, p + 801, -1); queue<int>q; q.push(src); p[src] = src; while (!q.empty()) { int cur = q.front(); q.pop(); int len = v[cur].size(); for (int i = 0; i < len; ++i) { int next = v[cur][i]; //유량이 남아있고 방문하지 않았다면, if (c[cur][next] - f[cur][next] > 0 && p[next] == -1) { p[next] = cur; q.push(next); if (next == dest) break; } } } if (p[dest] == -1) break; int minflow = 987654321; for (int i = dest; i != src; i = p[i]) minflow = min(minflow, c[p[i]][i] - f[p[i]][i]); //minflow만큼 흐르게 될것. for (int i = dest; i != src; i = p[i]) { f[p[i]][i] += minflow; f[i][p[i]] -= minflow; } ans += minflow; } return; } int main() { scanf("%d %d", &n, &m); //in 1~400, out 401 ~800.... //internal for (int i = 1; i <= n; ++i) { v[i].push_back(i + out); v[i + out].push_back(i); //i -> i+out.. c[i][i + out] = 1; } //external for (int i = 0; i < m; ++i) { int from, to; scanf("%d %d", &from, &to); v[out + from].push_back(to); v[to].push_back(out + from); v[to + out].push_back(from); v[from].push_back(to + out); // out <- > to c[out + from][to] = 1; c[to + out][from] = 1; } edmondkarp(); printf("%d", ans); return 0; }
6. 결과 사진

지적, 댓글 언제나 환영입니다~
'알고리즘 > Network flow' 카테고리의 다른 글
boj, 백준) 2367. 파티 (C/C++) (0) | 2021.07.06 |
---|---|
boj, 백준) 11495. 격자 0 만들기 ( C / C++ ) (0) | 2021.04.24 |
boj, 백준) 11406. 책 구매하기 2 ( C/C++) (0) | 2021.04.09 |
boj, 백준) 17412. 도시 왕복하기1 (C/C++) (0) | 2021.04.07 |
boj, 백준) 11378. 열혈강호 4 ( C / C++ ) (0) | 2020.03.24 |