IT/알고리즘
백준 알고리즘 | 14585 | 사수빈탕ㅣJava
황설모
2021. 7. 26. 17:13
문제
수빈이는 좌표평면 위에 앉아있다. "나는 좌표평면이 너무 좋아!!" 라고 수빈이가 말했다. 좌표평면에는 N개의 사탕바구니가 있고, 각 사탕 바구니에는 M개의 사탕이 있다. 각 사탕 바구니는 (x1, y1), (x2, y2), …, (xn, yn)에 있고, 수빈이는 (0, 0)에 있다.
오늘은 날씨가 덥다. 따라서 시간이 1만큼 지날 때마다 사탕이 남아 있는 모든 사탕바구니에서 사탕은 한 개씩 녹아서 없어진다. 수빈이는 매우 배가 고프기 때문에, 사탕바구니에 있는 사탕을 순식간에 모두 먹을 수 있다. 수빈이가 1만큼 움직일 때, 시간은 1만큼 지나간다. 수빈이는 위쪽 (y-좌표가 늘어나는 방향) 또는 오른쪽 (x-좌표가 늘어나는 방향)으로만 움직일 수 있다.
수빈이가 먹을 수 있는 사탕의 최대 개수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N과 M이 주어진다.
둘째 줄부터 N개의 줄에 사탕 바구니의 위치 xi, yi가 주어진다. (0 ≤ N ≤ 300, 1 ≤ M ≤ 1,000,000, 0 ≤ xi, yi ≤ 300)
사탕 바구니의 위치는 중복되지 않으며, (0, 0)에는 사탕이 없다.
출력
수빈이가 먹을 수 있는 사탕의 최대 개수를 출력한다.
예제
입력 | 출력 |
3 15 1 1 3 1 1 6 |
24 |
풀이
DP로 풀어보자
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class BOJ14585
{
static int n; // 사탕바구니의 수
static int m; // 사탕바구니 속 사탕의 수
static int [][] map ; // 사탕바구니 위치를 저장할 2차월 배열이며
// 0 ≤ xi, yi ≤ 300 이므로 크기는 301 x 301
static int [][] Record;
static int limit; // 사탕바구니를 모두 지나면 끝내기
static int xyMax; // 가장 멀리있는 바구니의 x,y 값 중 큰 값
static int ans;
public static void main (String[] args) throws java.lang.Exception
{
// your code goes here
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
n=Integer.parseInt(st.nextToken());
m=Integer.parseInt(st.nextToken());
xyMax=0;
map=new int[301][301];
Record=new int[301][301];
for(int i=0;i<n;i++)
{
st = new StringTokenizer(br.readLine());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
map[x][y]=m;
// 평면은 301 x 301 이지만 x,y가 존재하는 위치까지만 확인하기 위해 x,y 값 중 최대값 확인
if(x>=xyMax||y>=xyMax)
{
xyMax=Math.max(x,y);
}
}
ans = 0;
limit=0;
//(0,0) 위치부터 최댓값 확인
for(int i=0;i<=xyMax;i++)
{
for(int j=0;j<=xyMax;j++)
{
dp(i,j);
}
}
bw.write(ans+"\n");
br.close();
bw.flush();
bw.close();
}
static void dp(int i, int j)
{
// 사탕바구니를 모두 확인하였으면 종료
if(limit==n) return;
// 사탕바구니가 있는 위치라면 limit 증가
if(map[i][j]==300) limit++;
int right=0; // (i,j-1) 위치로부터 오른쪽(->)에 (i,j)가 위치, (i,j-1)의 최대값 변수
int up=0; // (i+1,j) 위치로부터 위쪽(^)에 (i,j)가 위치, (i+1,j)의 최대값 변수
//(i,j-1) 위치가 유효한 경우
if(i>=0&&i<301&&j-1>=0&&j-1<301)
{
right=Record[i][j-1];
}
//(i-1,j) 위치가 유효한 경우
if(i-1>=0&&i-1<301&&j>=0&&j<301)
{
up=Record[i-1][j];
}
// (i,j-1)과 (i-1,j) 중 큰 값 가져오기
Record[i][j]=Math.max(right,up);
// (i,j) 위치에 사탕이 있고 가는 동안(i+j) 녹지 않은 사탕이 있다면, 추가
if(map[i][j]-(i+j)>=0) Record[i][j]+=map[i][j]-i-j;
//최대값 확인
ans=Math.max(ans, Record[i][j]);
}
}
기타
다른 코드들을 참고해보니 0,0->x,y로 가는 방향보다, x,y에서 0,0로 오는 방향으로 계산하면 더 빠르게 계산할 수 있는 것 같다.