티스토리 뷰

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. 결과 사진

 

 

지적, 댓글 언제나 환영입니다~

댓글
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Total
Today
Yesterday