ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 12100번 - 2048(Easy)] C++ 풀이
    알고리즘/삼성SW역량테스트기출 2021. 9. 18. 22:02
    728x90
    반응형

    백준 12100번.

    https://www.acmicpc.net/problem/12100

     

    12100번: 2048 (Easy)

    첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2

    www.acmicpc.net

    예전에 많이 했던 게임인데 반갑네..

    그 게임과는 다르게, 블록이 새로 추가되거나 하지는 않고, 주어진 블록들을 가지고 같은 숫자 만나면 합치고 합쳐서 최대 5번까지 이동했을 때 최대 숫자를 출력하는 문제이다.

     

    사용한 알고리즘

    - 시뮬레이션

    - dfs

    - 구현

     

    음.. 또 다 해봐야지.. 라는 생각밖에 안들었다. 백트래킹으로 promising 하지 않는 경우의 수를 가지치기 할 수 있으면 효율이 더 좋아질것같다. 뭐, promising 조건으로 생각나는건, 같은 숫자가 연속으로 있지 않아서 합칠 수 없는 경우? 정도가 될 것 같다.

    우선은 그냥 최대 5번 움직이라고 했으니 무조건 count 가 5가 되면 최대값 계산하는 방식으로 구현하였다. 

     

    shift 함수에서는 k 값에 따라 왼/위/오/아 로 밀고 합칠 수 있는 블록을 합쳐 그 map 을 반환하는 함수이다.

    2차원 벡터 v에 합칠 방향에 따라 map 에서 0이아닌 값을 push_back 한다. 그리고 합칠 수 있는 블록을 찾아서 합치고, 다시 v 를 map 에 민 방향에 맞게 대입하고 빈 부분은 0으로 채운다. v 를 새로 만든 이유는, 한 방향으로 밀고 나서, 서로 합쳐진 블록중 하나 없애야 하는데 이 작업을 그대로 map 에 하게되면 너어무 복잡해질 것 같아 v를 만들고 해당 인덱스는 erase해주는 방식을 이용했다.

    dfs 이용해서 방향에 따라 shift 함수를 재귀적으로 호출하고, count == 5 이면 반환한다.

    해당 열이나 행에 0만 있는 경우에 v 에 0을 push 해줘야 하는데 그 경우를 고려 안해서 한번 틀렸다.. 

    코드가 조금 많이 길고 더럽다ㅜㅜ

     

    완성된 코드

    #include <stdio.h>
    #include <vector>
    
    using namespace std;
    
    int n;
    int ans = 0;
    
    vector<vector<int>> shift(int k, vector<vector<int>> map) {
    	vector<vector<int>> v;
    	v.assign(n + 1, vector<int>());
    
    	if (k == 0) { // 왼쪽으로 밀기
    		for(int i = 0; i < n; ++i) {
    			bool isAllZero = true;
    			for(int j = 0; j < n; ++j) {
    				if (map[i][j] != 0) {
    					v[i].push_back(map[i][j]);
    					isAllZero = false;
    				}
    			}
    			if (isAllZero) {
    				v[i].push_back(0);
    			}
    		}
    	} else if (k == 1) { // 오른쪽으로 밀기
    		for(int i = 0; i < n; ++i) {
    			bool isAllZero = true;
    			for(int j = n - 1; j >= 0 ; --j) {
    				if (map[i][j] != 0) {
    					v[i].push_back(map[i][j]);
    					isAllZero = false;
    				}
    			}
    			if (isAllZero) {
    				v[i].push_back(0);
    			}
    		}
    	} else if (k == 2) { // 위로 밀기
    		for(int j = 0; j < n; ++j) {
    			bool isAllZero = true;
    			for(int i = 0; i < n; ++i) {
    				if (map[i][j] != 0) {
    					v[j].push_back(map[i][j]);
    					isAllZero = false;
    				}
    			}
    			if (isAllZero) {
    				v[j].push_back(0);
    			}
    		}
    	} else if (k == 3) { // 아래로 밀기
    		for(int j = 0; j < n ; ++j) {
    			bool isAllZero = true;
    			for(int i = n - 1; i >= 0; --i) {
    				if (map[i][j] != 0) {
    					v[j].push_back(map[i][j]);
    					isAllZero = false;
    				}
    			}
    			if (isAllZero) {
    				v[j].push_back(0);
    			}
    		}
    	}
    
    	for(int i = 0; i < n; ++i) {
    		int temp = v[i][0];
    		for(int j = 1; j < v[i].size(); ++j) {
    			if (v[i][j] == 0)
    				break;
    			else if (temp == v[i][j]) {
    				v[i][j - 1] = temp * 2;
    				vector<int>::iterator it = v[i].begin();
    				v[i].erase(it + j);
    				temp = v[i][j]; // 다음걸로 갱신
    			} else {
    				temp = v[i][j];
    			}
    		}
    	}
    
    	if (k == 0) {
    		for(int i = 0; i < n; ++i) {
    			for(int j = 0; j < v[i].size(); ++j) {
    				map[i][j] = v[i][j];
    			}
    			for(int j = v[i].size(); j < n; ++j) {
    				map[i][j] = 0;
    			}
    		}
    	}
    	else if (k == 1) {
    		for(int i = 0; i < n; ++i) {
    			for(int j = 0; j < v[i].size(); ++j) {
    				map[i][n - 1 - j] =v[i][j];
    			}
    			for(int j = v[i].size(); j < n; ++j) {
    				map[i][n - 1 - j] = 0;
    			}
    		}
    	}
    	else if (k == 2) {
    		for(int i = 0; i < n; ++i) {
    			for(int j = 0; j < v[i].size(); ++j) {
    				map[j][i] = v[i][j];
    			}
    			for(int j = v[i].size(); j < n; ++j) {
    				map[j][i] = 0;
    			}
    		}
    	}
    	else if (k == 3) {
    		for(int i = 0; i < n; ++i) {
    			for(int j = 0; j < v[i].size(); ++j) {
    				map[n - 1 - j][i] = v[i][j];
    			}
    			for(int j = v[i].size(); j < n; ++j) {
    				map[n - 1 - j][i] = 0;
    			}
    		}
    	}
    	return map;
    }
    
    void dfs(int cnt, vector<vector<int>> map) {
    	if (cnt == 5) {
    		// 해당 map 에서의 최대값 구하기
    		for(int i = 0; i < n; ++i) {
    			for(int j = 0; j < n; ++j) {
    				if (ans < map[i][j]) {
    					ans = map[i][j];
    				}
    			}
    		}
    		return;
    	} else {
    		for(int i = 0; i < 4; ++i) {
    			dfs(cnt + 1, shift(i, map));
    		}
    	}
    }
    
    int main() {
    	scanf("%d", &n);
    	vector<vector<int>> map;
    
    	map.assign(n + 1, vector<int>(n + 1, 0));
    	for(int i = 0; i < n; ++i) {
    		for(int j = 0; j < n; ++j) {
    			scanf("%d", &map[i][j]);
    		}
    	}
    
    	//최대 5번 움직인다.
    	dfs(0, map);
    
    	printf("%d\n", ans);
    	return 0;
    }

     

     

    728x90

    댓글

Designed by Tistory.