알고리즘/acmicpc
1937
kwony
2016. 9. 6. 18:50
모든 경로를 탐색하려고 하면 경우의 수가 무척 많아져서 어렵다. 여기서는 문제의 조건을 잘 살펴야 한다.
- 판다는 상,하,좌,우 중 하나의 경로로 이동한다
- 대나무의 양은 증가하는 순서여야 한다.
위 두가지 조건만을 이용해서 dp를 만들어 줄 수 있다.
dp[x][y]는 어떤 위치(x,y)로 도달 할 때 판다가 최대 살 수 있는 일 수를 가지고 있다고 하자.
그럼 다음과 같은 점화식을 적용 할 수 있다.
dp[x][y] = (상하좌우에 있는 대나무중 현재 위치의 대나무보다 양이 작은 값들의 dp중 가장 큰 것) + 1
이해를 돕기 위해 그림으로 부연 설명을 하면..
파란색으로 칠해둔 위치의 dp값을 업데이트 하려고 한다. 이때 파란색 위치로 접근 할 수 있는 경로는 (x,y)위치의 상하좌우중 (x,y)의 위치보다 대나무 수가 적은 곳(상, 우)이다. 상, 우의 dp값중 가장 큰 값(2)에서 하루를 더 살 수 있는 것으로 (x,y)의 위치에 도달 할 때는 판다는 최대 3일을 살 수 있다.
위 알고리즘을 적용하려면 대나무의 수가 적은 순서대로 탐색을 해야한다. 그렇지 않으면 중간에 누락되는 경로가 생길 수 있다.
반드시 대나무가 증가하는 순서대로 진행되므로 circle이 생기지 않기 때문에 위 알고리즘 만으로 모든 경우를 포함 할 수 있다.
#include<cstdio>
#include<algorithm>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
struct Node {
int val, r, c;
};
int map[505][505];
int dp[505][505];
Node node[500 * 500];
int dr[4] = { 0, 1, 0, -1 };
int dc[4] = { 1, 0, -1, 0 };
bool compare(Node a, Node b) {
if (a.val < b.val)
return true;
return false;
}
int main() {
int N, i, j, nr;
int r, c, val, ans;
scanf("%d", &N);
nr = 0;
for (i = 1; i <= N; i++){
for (j = 1; j <= N; j++) {
scanf("%d", &map[i][j]);
node[nr].r = i;
node[nr].c = j;
node[nr++].val = map[i][j];
}
}
sort(&node[0], &node[nr], compare);
ans = 0;
for (int i = 0; i < nr; i++) {
r = node[i].r, c = node[i].c, val = node[i].val;
dp[r][c] = 1;
for (int j = 0; j < 4; j++) {
if (map[r][c] > map[r + dr[j]][c + dc[j]]) {
dp[r][c] = MAX(dp[r][c], dp[r + dr[j]][c + dc[j]] + 1);
ans = MAX(ans, dp[r][c]);
}
}
}
printf("%d\n", ans);
return 0;
}