Notice
250x250
Recent Posts
Recent Comments
Link
넘치게 채우기
[BOJ] 1080: 행렬 본문
728x90
반응형
https://www.acmicpc.net/problem/1080
BOJ - 1080: 행렬
문제 유형 : 행렬, 그리디, 비트마스크
문제 난이도 : Silver I
문제
0과 1로만 이루어진 행렬 A와 행렬 B가 있다. 이때, 행렬 A를 행렬 B로 바꾸는데 필요한 연산의 횟수의 최솟값을 구하는 프로그램을 작성하시오.
행렬을 변환하는 연산은 어떤 3×3크기의 부분 행렬에 있는 모든 원소를 뒤집는 것이다. (0 → 1, 1 → 0)
입력
첫째 줄에 행렬의 크기 N M이 주어진다. N과 M은 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 행렬 A가 주어지고, 그 다음줄부터 N개의 줄에는 행렬 B가 주어진다.
출력
첫째 줄에 문제의 정답을 출력한다. 만약 A를 B로 바꿀 수 없다면 -1을 출력한다.
풀이
이 문제는 그리디로 풀 수 있다.
우선, 행렬은 하나만 만들어서 A행을 우선 저장한 뒤, B행의 값을 xor시키면 된다. 두 행렬의 비트차가 중요하니까, 이 정보면 충분하다.
이제 이 행렬을 모두 0으로 만들면 된다.
좌측 상단부터 우측 하단순으로 행우선으로 각 칸을 확인하면서, 칸이 1이면 그 칸을 왼쪽 맨 위로 하여 3 * 3의 크기를 비트 플립하면 된다.
다 끝나고도 아직 1이 남아있다면, 불가능하므로 -1을 출력하고, 아니라면 비트플립 횟수를 출력하면 된다.
코드
C++
#include <iostream>
#include <vector>
using namespace std;
int n, m;
void flip(int row, int col, vector<vector<int>>& mat) {
for(int i = 0; i < 3; ++i) {
for(int j = 0; j < 3; ++j) {
mat[row + i][col + j] ^= 1;
}
}
}
bool isFinished(vector<vector<int>>& mat) {
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(mat[i][j]) return false;
}
}
return true;
}
int main() {
cin >> n >> m;
vector<vector<int>> mat(n, vector<int>(m));
string temp;
for(int i = 0; i < n; ++i) {
cin >> temp;
for(int j = 0; j < m; ++j) {
mat[i][j] = temp[j] - '0';
}
}
for(int i = 0; i < n; ++i) {
cin >> temp;
for(int j = 0; j < m; ++j) {
mat[i][j] ^= temp[j] - '0';
}
}
int cnt = 0;
for(int i = 0; i < n-2; ++i) {
for(int j = 0; j < m-2; ++j) {
if(mat[i][j] == 1) {
flip(i, j, mat);
cnt++;
}
}
}
if(isFinished(mat)) {
cout << cnt << "\n";
} else {
cout << -1 << "\n";
}
return 0;
}
728x90
반응형
'PS > BOJ' 카테고리의 다른 글
[BOJ] 25342: 최대 최소공배수 (0) | 2024.09.26 |
---|---|
[BOJ] 23631: 진심 좌우 반복뛰기 (0) | 2024.09.25 |
[BOJ] 28360: 양동이 게임 (0) | 2024.09.23 |
[BOJ] 21558: 전쟁 준비하기 (0) | 2024.09.22 |
[BOJ] 4531: Verdis Quo (0) | 2024.09.20 |