티스토리 뷰
1. 문제 링크
https://www.acmicpc.net/problem/1867
1867번: 돌멩이 제거
문제 n행 n열의 격자로 나뉜 운동장이 있다. 이 위에 k개의 돌멩이가 있는데, 하나의 돌멩이는 격자 한 칸에 정확히 들어가 있으며, 두 개 이상의 돌멩이가 한 칸에 들어가 있는 경우는 없다. 사고의 위험을 없애기 위해 이 돌멩이를 모두 제거하고 깨끗한 운동장을 만들려고 한다. 돌멩이를 제거할 때에는, 한 행이나 한 열을 따라 직선으로 달려가면서 그 행이나 열에 놓인 돌멩이를 모두 줍는 방식을 쓴다. 여러분이 할 일은 운동장의 상태가 주어졌을 때 최소 몇
www.acmicpc.net
2. 문제 개요
한 번에 하나의 행이나, 하나의 열 중 하나를 골라서 정리할 때, 최소로 움직여서 모든 돌을 치우는 방법.
3. 문제 힌트
최소 버텍스 커버 유형입니다.
행의 집합, 열의 집합으로 이루어진 그래프는 이분 그래프의 모양을 띄고,
간선(돌)을 모두 커버 할 수 있는 것.
4. 문제 풀이
처음에 문제를 봤을 때 최소 버텍스 커버 유형의 문제일 거라 예상했습니다만,
'간선'이 의미하는 바가 뭔지 명확하게 몰라 풀고 나서도 많이 생각했던 문제였습니다.
1번의 실행 단위가 행 or열입니다.
(문제의 예제로 가정) 9개로 나뉘어있는 한 칸 한 칸을 정점이라 보지 말고
하나의 실행 단위인 행 과열을 정점으로 생각합시다. 그리고 간선을 돌멩이라고 생각해봅시다.
Vertex cover의 의미는 집합 S에서 부분집합 S`를 골랐을 때, 그 집합 S`가 모든 간선을 커버하는가를 의미합니다.
즉, 최소 버텍스 커버는 모든 간선(돌멩이)을 커버하느냐를 의미하고, 모든 돌멩이를 주울 수 있느냐로 바꿀 수 있습니다.
따라서 돌멩이가 있는 행, 열( i , j )은 i행 j열 정점을 연결해줍니다.
5. 코드
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int ans = 0;
int adj[501][501];
int group[2][501][501];
int groupcount[2] = { 0,0 };
int map[501][501];
int n, k;
bool visited[501];
int p[501];
bool dfs(int cur)
{
if (visited[cur])
return false;
visited[cur] = true;
for (int next = 0; next < groupcount[1]; ++next)
{
if (adj[cur][next] == 1){
if (p[next] == -1 || dfs(p[next]))
{
p[next] = cur;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d %d", &n, &k);
for (int i = 0; i < k; ++i){
int y, x;
scanf("%d %d", &y, &x);
map[y - 1][x - 1] = 1;
}
memset(group, -1, sizeof(group));
memset(p, -1, sizeof(p));
//가로 집합만들기
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j)
{
if (map[i][j] == 1)
group[0][i][j] = groupcount[0];
}
groupcount[0]++;
}
for (int j = 0; j < n; ++j) {
for (int i = 0; i < n; ++i)
{
if (map[i][j] == 1)
group[1][i][j] = groupcount[1];
}
groupcount[1]++;
}
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
if (map[i][j] == 1)
adj[group[0][i][j]][group[1][i][j]] = 1;
for (int i = 0; i < groupcount[0]; ++i)
{
memset(visited, false, sizeof(visited));
if (dfs(i))
ans++;
}
printf("%d", ans);
return 0;
}
여기서는 인접 행렬을 사용했지만, 인접 리스트를 쓰는 것도 별로 어렵지 않습니다!!
6. 결과 사진
지적, 댓글 언제나 환영입니다~
'알고리즘 > Minimum vertex cover' 카테고리의 다른 글
boj, 백준) 2051. 최소 버텍스 커버 ( C / C++) (0) | 2020.07.12 |
---|