티스토리 뷰

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

 

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

댓글
«   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