공부 기록

C++ 백준 1080번

by 너나나

백준 1080번 www.acmicpc.net/problem/1080

 

1080번: 행렬

첫째 줄에 행렬의 크기 N M이 주어진다. N과 M은 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 행렬 A가 주어지고, 그 다음줄부터 N개의 줄에는 행렬 B가 주어진다.

www.acmicpc.net

문제 : 0과 1로만 이루어진 행렬 A와 행렬 B가 있다. 이때, 행렬 A를 행렬 B로 바꾸는데 필요한 연산의 횟수의 최솟값을 구하는 프로그램을 작성하시오.

행렬을 변환하는 연산은 어떤 3*3 크기의 부분 행렬에 있는 모든 원소를 뒤집는 것이다. (0 -> 1, 1 -> 0)

 

그러니까 1과 0으로만 이루어진 어떤 행렬 A의 3*3 부분을 정해서 그 안의 수를 1->0, 0->1로 바꾸는데 이 행동을 몇 번 반복하는지의 최솟값을 구하면 된다. 아이디어만 잘 생각하면 어렵지 않은데

예를 들어 5*5크기의 행렬을 생각해보자

         
         
         
         
         

이 행렬에서

1        
         
         
         
         

 

저기 맨 위 왼쪽의 1을 0으로 바꾸기 위해서는 

 

이렇게 3*3을 바꾸는거 말고는 방법이 없다.

계속 제일 왼쪽 위를 기준으로 하나씩 옮겨가면서 숫자를 바꾸자.

         
         
    1    
         
         

마지막으로 이 1을 바꿀려면

이렇게 3*3을 바꾸면 되는데 이런 식으로 맨 왼쪽 위를 기준으로 옮기면 더 이상 바꿀 수 있는 숫자가 없다.

결국 저 하얀 부분을 우리가 원하는 행렬이랑 똑같이 만들었을 때 저 파란 부분의 숫자도 같아지면 행렬 A를 행렬B로 바꿀 수 있는거고, 숫자가 다르면 저중에 숫자 하나를 바꾸면 하얀부분의 숫자가 달라지므로 행렬A를 B로 바꿀수 없다.

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
using namespace std;
int a[51][51];
int b[51][51]; // 원하는 행렬
int main() {
	int n, m;
	scanf("%d %d", &n, &m);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			scanf("%1d", &a[i][j]);
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			scanf("%1d", &b[i][j]);
		}
	}
	int ans = 0;
	for (int i = 0; i < n - 2; i++) {
		for (int j = 0; j < m - 2; j++) {
			if (a[i][j] != b[i][j]) {
				for (int k = i; k <= i + 2; k++) {
					for (int l = j; l <= j + 2; l++) {
						a[k][l] = 1 - a[k][l]; // 1이면 0으로, 0이면 1로
					}
				}
				ans += 1;
			}
			else continue;
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (a[i][j] != b[i][j]) {
				printf("-1\n");
				return 0;
			}
		}
	}
	printf("%d\n", ans);
	return 0;
}

'study > 알고리즘' 카테고리의 다른 글

C++ 백준 12813번  (0) 2021.02.23
C++ 백준 2138번  (0) 2021.02.16
C++ 백준 11047번  (0) 2021.02.15
C++ 백준 16928번  (0) 2021.02.10
C++ 백준 4949번  (0) 2021.01.25

블로그의 정보

공부 기록

너나나

활동하기