* 요약
- 차원을 2차원으로 바꾸는힘
- i*m + j 암기!!!!
i*m + j
공식이 어떻게 2차원 배열을 1차원으로 변환하는지 설명
예를 들어 2x3 배열이 있다고 해보죠:
1 2 3
4 5 6
이 공식이 작동하는 방식을 단계별로 설명하겠습니다:
- 각 행(i)마다 건너뛰어야 하는 개수:
- 첫 번째 행(i=0): 0개 건너뜀 (0*m)
- 두 번째 행(i=1): m개 건너뜀 (1*m)
- 세 번째 행(i=2): 2m개 건너뜀 (2*m)
- 열 위치(j)를 더하기:
- j=0: 첫 번째 열
- j=1: 두 번째 열
- j=2: 세 번째 열
- 예시로 (1,2) 위치의 경우:
- i=1, j=2, m=3일 때
- 1*3 + 2 = 5
- 즉, 1차원 배열에서 5번 위치가 됨
이렇게 변환하는 이유:
- 비트마스크는 1차원으로만 동작
- 2차원 위치를 1차원으로 고유하게 매핑해야 함
- 각 위치가 겹치지 않고 순서대로 매핑되어야 함
실제 사용 예:
if(subset & (1<<(i*m+j))) {
// i행 j열 위치가 1인지 확인
}
이 공식은 2차원 배열을 행 우선(row-major) 순서로 1차원으로 펼치는 표준적인 방법입니다.
- 비트로 가로, 세로를 표현하는것이 조금 발상적.
* 숫자 배열의 가로/세로 합 최대화 알고리즘
문제 설명
N x M 크기의 숫자 배열이 주어졌을 때, 각 행은 가로로 읽거나 세로로 읽어서 만들 수 있는 합의 최대값을 구하는 문제입니다.
입력 예시
1 2 3
4 5 6
핵심 아이디어: 비트마스크를 이용한 상태 표현
1. 비트마스크 표현 방식
- 각 위치를 0 또는 1로 표현하여 해당 위치를 가로로 읽을지(1) 세로로 읽을지(0) 결정합니다.
- N x M 배열의 경우 총 N*M 비트가 필요합니다.
예시: 2x3 배열의 경우
위치 인덱스: 비트 위치:
0 1 2 5 4 3
3 4 5 2 1 0
2. 비트마스크 해석 방법
- 110001(2) 의 경우:
1 1 0 // 1: 가로로 읽음 0 0 1 // 0: 세로로 읽음
- 첫 번째 줄의 '11'은 첫 두 숫자를 가로로 연결해서 읽는다는 의미
- '0'은 그 위치의 숫자를 세로로 읽는다는 의미
알고리즘 동작 과정
1. 모든 가능한 조합 생성
int N = n*m;
for(int subset = 0; subset < (1<<N); ++subset) {
// 각 조합에 대해 계산
}
- 총 2^(N*M)개의 조합이 생성됨
- (1<<N)은 2^N을 의미
2. 가로 합 계산
// 각 행에 대해
for(int i=0; i<n; ++i) {
int sum = 0;
for(int j=0; j<m; ++j) {
// i*m + j: 2차원 배열의 위치를 1차원으로 변환
if(subset & (1<<(i*m+j))) {
sum = sum*10 + arr[i][j]; // 가로로 연결된 숫자 생성
} else {
garo_sum += sum; // 이전까지의 합을 더함
sum = 0; // 새로운 숫자 시작
}
}
garo_sum += sum; // 마지막 남은 숫자 더하기
}
3. 세로 합 계산
// 각 열에 대해
for(int j=0; j<m; ++j) {
int sum = 0;
for(int i=0; i<n; ++i) {
if(!(subset & (1<<(j+i*m)))) { // 비트가 0인 경우
sum = sum*10 + arr[i][j];
} else {
sero_sum += sum;
sum = 0;
}
}
sero_sum += sum;
}
시간 복잡도 분석
- 총 조합의 수: O(2^(N*M))
- 각 조합별 계산: O(N*M)
- 전체 시간 복잡도: O(2^(N_M) * (N_M))
구현시 주의사항
- 비트 연산자 우선순위
1<<(i*m+j)
에서 괄호 필수- 비트 시프트 연산자는 덧셈/뺄셈보다 우선순위가 낮음
- 숫자 연결 처리
sum = sum*10 + arr[i][j]
로 연속된 숫자를 하나의 수로 만듦- 예: 1, 2, 3을 차례로 연결하면 123이 됨
- 남은 숫자 처리
- 각 행/열의 계산이 끝난 후 남은 sum을 반드시 더해줘야 함
- 마지막 숫자 그룹이 처리되지 않을 수 있음
최적화 팁
- 입력 크기가 작은 경우에만 사용 가능
- N, M이 커지면 다른 알고리즘 고려 필요
- 메모이제이션을 통한 최적화 가능
* 최종코드
#include <bits/stdc++.h>
using namespace std;
int n,m, arr[5][5], ret;
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >>n>> m;
for(int i=0;i<n;++i) {
string s;
cin>>s;
for(int j=0;j<m;++j) {
arr[i][j]=s[j]-'0';
}
}
int N = n*m;
for(int subset = 0; subset < (1<<N);++subset) {
int garo_sum=0;
for(int i=0;i<n;++i) {
int sum=0;
for(int j=0;j<m;++j) {
/**
* m=3
* 0 1 2 / 0(i) * m + 0(j), 0*m+1, 0*m+2
* 3 4 5 / 1 * m + 0, ...
* 6 7 8
*/
if(subset & (1<<(i*m+j))) {
sum = sum*10 + arr[i][j];
}
else {
garo_sum +=sum;
sum=0;
}
}
garo_sum += sum; // Add remaining sum
}
int sero_sum=0;
for(int j=0;j<m;++j) {
int sum=0;
for(int i=0;i<n;++i) {
if(!(subset & (1<<(j+i*m)))) {
sum = sum*10 + arr[i][j];
}
else {
sero_sum +=sum;
sum=0;
}
}
sero_sum += sum; // Add remaining sum
}
ret = max(ret, garo_sum + sero_sum);
}
cout<<ret;
return 0;
}
'Algorithm > 비트마스킹' 카테고리의 다른 글
[알고리즘] 백준 2234 성곽 // 비트마스킹, vis의 값에 의미를 부여하라, i번째 비트끄기 (0) | 2025.01.12 |
---|---|
[알고리즘] 백준 1062 가르침 // 조합, 비트마스킹, 백트래킹 (0) | 2025.01.11 |
[알고리즘] 백준 1987 알파벳 // 비트마스킹, i번째 비트켜짐확인, vis를 숫자1개로 나타내는 힘 (0) | 2025.01.11 |
[알고리즘] 백준 19942 다이어트 // 비트마스킹, 1-idx (0) | 2025.01.11 |
[알고리즘] 백준 17471 게리멘더링 // 비트마스킹, dfs 구역체크는 노드1곳에서 시작 (0) | 2025.01.08 |