N :구슬을 쏠 수 있는 횟수 (1~4)
W : col 정보, 가로 (2~12)
H : row 정보, 세로 (2~15)
HxW 전체 맵 크기, Map[r][c]은 빈 칸(0) 혹은 벽돌(1~9)로 구성됨
게임의 규칙{
구슬은 항상 맨 위에 있는 벽돌만 깰 수 있음
(%)벽돌은 본인 위치에서 상하좌우 (벽돌 숫자-1)만큼의 범위를 가짐
범위 내에 있는 벽돌은 동시에 제거됨
연쇄작용으로 인해 구슬은 제거되면서 (%)을 수행함
빈 공간이 발생할 경우 벽돌은 밑으로 떨어짐
}
원하는 것 = 게임 시뮬레이션 후 최대한 많은 벽돌을 제거했을 때 남은 벽돌의 개수를 출력
input_1 테스트 케이스 T 입력 받기
input_2_1 N,W,H 입력 받기
input_2_2 초기 맵 정보 Map[15][12]를 입력받음
재귀호출 함수를 이용해서 모든 경우의 수 (= W^N) 구현하기
한 세로줄이 모두 빈칸일 경우 그 곳은 벽돌을 깰 수 없으므로 경우에서 배제
DFS 이용해서 벽돌 숫자에 따라 벽돌이 파괴되고 연쇄작용이 일어나는 것까지 구현
빈 칸이 있을 경우 밑으로 떨어뜨리기
깨트린 벽돌의 최댓값 구하기
res = 처음 - 깨트린 벽돌
output "#n" + res 출력하기
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int T;
int N,W,H;
int Map[5][15][12];
int Dr[4] = {0,0,1,-1};
int Dc[4] = {1,-1,0,0};
void drop(int cnt){
queue<int> Q;
for(int j = 0; j < W; j++){
for(int i = H-1; i >= 0; i--){
if(Map[cnt][i][j]){
Q.push(Map[cnt][i][j]);
Map[cnt][i][j] = 0;
}
}
for(int i = H-1; Q.size(); --i, Q.pop())//i > H-1-q.size
Map[cnt][i][j] = Q.front();
}
}
int DFS(int r, int c, int cnt){
int dis = Map[cnt][r][c];////
int res = 1;
Map[cnt][r][c] = 0;
for(int i = 0; i < dis; i++){
for(int j = 0; j < 4; j++){
int nr = r + Dr[j]*i;
int nc = c + Dc[j]*i;
if(nr < 0 || nc < 0 || nr > H-1 || nc > W-1 || Map[cnt][nr][nc]==0) continue;
res += DFS(nr,nc,cnt);
}
}
return res;
}
void cpy (int cnt){
for(int i = 0; i < H; i++)
for(int j = 0; j < W; j++)
Map[cnt][i][j] = Map[cnt-1][i][j];
}
int solve(int cnt){
if(cnt > N) return 0;
int res = 0;
for(int i = 0; i < W; i++){
cpy(cnt);
int temp = 0;
bool flag = true;
for(int j = 0; j < H; j++){
if(Map[cnt][j][i]==0) continue;
flag = false;
temp = DFS(j,i,cnt);
break;
}
if(flag) continue;
drop(cnt);
res = max(res, solve(cnt+1)+temp);
}
return res;
}
int main()
{
cin >> T;
for(int t = 0; t < T; t++){
cin >> N >> W >> H;
int sum = 0;
for(int i = 0; i < H; i++){
for(int j = 0; j < W; j++){
cin >> Map[0][i][j];
sum += Map[0][i][j] ? 1 : 0;
}
}
int res = sum - solve(1);
cout << "#" << t+1 << " " << res << '\n';
}
return 0;
}
백업_0604_pm 04:00
dfs 고쳤는데도 오류 발생, 1번 슈팅은 값 잘 나오는데, 2회 이상부터는 null 반환됨
#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 98456154
struct loc{
int r,c,dis;
};
int T, N, W, H;
int Map[15][12];
int Bsize[12];
int Dr[4] = {0,1,0,-1};
int Dc[4] = {1,0,-1,0};
int res = INF;
int calculate(){
int sum = 0;
for(int i = 0; i < H; i++)
for(int j = 0; j < W; j++)
if(Map[i][j] > 0) sum++;
return sum;
}
void shoot(int pos){
//맵 삭제 + 빈칸 없애기+Bsize도 반영시켜야 함
//처음 맞은 곳 0으로 만들고, 큐에 넣음
queue<loc> myqueue;
int idx = H-Bsize[pos];
int dis = Map[idx][pos]-1;
Map[idx][pos] = 0;
Bsize[pos]--;
myqueue.push({idx,pos,dis});
//연쇄 작용인한 것 처리하기
do{
loc curr = myqueue.back();
myqueue.pop();
//4방향에 대해서 살펴봄
for(int i = 0; i < 4; i++){
int nr = curr.r, nc = curr.c;
//서비스 범위까지 적용
for(int j = 0; j < curr.dis; j++){
nr += Dr[i];
nc += Dc[i];
if(Map[nr][nc] == 0) continue;
int dis = Map[nr][nc]-1;
Map[nr][nc] = 0;
Bsize[nc]--;
if(dis == 0) continue;
myqueue.push({nr,nc,dis});
}
}
}while(!myqueue.empty());
//빈칸 생긴 거 없애주기
for(int i = 0; i < W; i++){//col
if(Bsize[i] == 0) continue;
for(int j = 0; j < Bsize[i]; j++){//블럭 개수
int lowest = 0;//가장 낮은 빈칸
for(int k = H-1; k >= 0; k--){//row
if(Map[k][i] == 0) lowest = max(lowest,k);
else{
if(lowest == 0) continue;
else{
Map[lowest][i] = Map[k][i];
lowest = 0;
Map[k][i] = 0;
break;
}
}
}
}
}
return;
}
void solve(int cnt){
if(cnt>=N){
res = min(res, calculate());
return;
}
int copy[15][12];
int copyBsize[12];
for(int i = 0; i < W; i++){
if(Bsize[i] <= 0) continue;
//초기 맵 카피 해두기
memcpy(copy, Map, sizeof(Map));
memcpy(copyBsize, Bsize, sizeof(Bsize));
shoot(i);
solve(cnt+1);
//개수 최솟값인지 비교
//맵 복원
memcpy(Map, copy, sizeof(Map));
memcpy(Bsize, copyBsize, sizeof(Bsize));
}
}
int main()
{
cin >> T;
for(int t = 0; t < T; t++){
cin >> N >> W >> H;
memset(Map, 0, sizeof(Map));
memset(Bsize,0,sizeof(Bsize));
for(int i = 0; i < H; i++){
for(int j = 0; j < W; j++){
cin >> Map[i][j];
if(Map[i][j] > 0) Bsize[j]++;
}
}
solve(0);
cout << "#" << t+1 << " " << res << endl;
}
return 0;
}