이 페이지는 코딩도장 데이터의 읽기 전용 정적 보관본입니다.

욕심쟁이 판다

출처 : https://www.acmicpc.net/problem/1937

n*n의 크기의 대나무 숲이 있다. 그리고 각 지역마다 대나무의 양이 다르다. 그런데 욕심쟁이 판다는 어떤 지역에서 대나무를 먹기 시작한다. 그리고 그 곳의 대나무를 다 먹어 치우면 상, 하, 좌, 우 중 한 곳으로 이동을 한다. 그리고 또 그곳에서 대나무를 먹는다. 그런데 단 조건이 있다. 이 판다는 매우 욕심이 많아서 대나무를 먹고 자리를 옮기면 그 옮긴 지역에 그 전 지역보다 대나무가 많이 있어야 한다. 만약에 그런 지점이 없으면 이 판다는 불만을 가지고 단식 투쟁을 하다가 죽게 된다(-_-)

이 판다의 사육사는 이런 판다를 대나무 숲에 풀어 놓아야 하는데, 어떤 지점에 처음에 풀어 놓아야 하고, 어떤 곳으로 이동을 시켜야 둘 다 소중한 생명이지만 판다가 최대한 오래 살 수 있는지 고민에 빠져 있다. 우리의 임무는 이 사육사를 도와주는 것이다. n*n 크기의 대나무 숲이 주어져 있을 때, 이 판다가 최대한 오래 살려면 어떤 경로를 통하여 움직여야 하는지 구하여라.

입력

첫째 줄에 대나무 숲의 크기 n(1<=n<=500)이 주어진다. 그리고 둘째 줄부터 1+n번째 줄 까지 대나무 숲의 정보가 주어진다. 대나무 숲의 정보는 공백을 사이로 두고 각 지역의 대나무의 양이 정수 값으로 주어진다.

출력

첫째 줄에는 판다가 최대한 살 수 있는 일수(K)를 출력한다.

예제 입력

4
14 9 12 10
1 11 5 4
7 15 2 13
6 3 16 8

예제 출력

4
다이나믹 프로그래밍 최장 증가 부분열(LIS)

2016/06/02 19:35

iljimae

대나무를 먹는 시간이 없네요. 한 곳에 있는 대나무를 다 먹는 데 대나무 양에 상관없이 하루가 걸린다... 라고 생각하면 되겠죠? - Noname, 2017/08/20 22:18

23개의 풀이가 있습니다.

어떠한 수열이 주어졌을때 이 수열의 최장 증가 부분열을 찾는것은 다이나믹 프로그래밍으로 해결할 수 있는 유명한 문제입니다.

참고자료 http://dyngina.tistory.com/16

이 문제는 2차원 배열에 대해서 최장 증가 부분열 알고리즘을 적용하면 됩니다. 모든 n*n점 (i,j)에 대해서 판다의 시작점을 정해준뒤에 dfs로 탐색하면서 얻을 수 있는 가장 긴 증가하는 수열의 길이를 얻으면 됩니다.

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <algorithm> 
using namespace std;

int forest[501][501];  
int dp[501][501]; 
int dy[4] = {1,0,-1,0}; 
int dx[4] = {0,1,0,-1};  
int n; 

bool inRange(int y,int x){
    return (y >= 0 && y < n && x >= 0 && x < n); 
}

int find(int y,int x){
    if (dp[y][x] == 0){
        dp[y][x] = 1; 
        for (int i = 0; i < 4; i++){
            int ny = y+dy[i], nx = x+dx[i];  
            if (inRange(ny,nx) && forest[ny][nx] > forest[y][x]){
                dp[y][x] = max(dp[y][x],find(ny,nx)+1); 
            }
        }
    }
    return dp[y][x];  
}

int main(){
    scanf("%d",&n);  
    for (int i = 0; i < n; i++){
        for (int j = 0; j < n; j++){
            scanf("%d",&forest[i][j]);  
        }
    }
    // dp 테이블 채우기  
    int res = 0;  
    for (int i = 0; i < n; i++){
        for (int j = 0; j < n; j++){ // 팬더의 시작좌표를 정해주고 최댓값을 갱신한다.  
            res = max(res,find(i,j));  
        }
    }
    printf("%d\n",res);  
    return 0; 
}

2016/06/02 20:09

iljimae

Ruby

def max_trail(bamboos, n=[*0...bamboos.size])
  trees = n.product(n).map {|x,y| [y,x,bamboos[x][y]] }
  nexts = ->x,y,v { trees.select {|ex,ey,ev| (ex-x).abs+(ey-y).abs <2 && ev>v} }
  trail = ->t,max=0 { t[0] ? trail[t.flat_map{|e|nexts[*e]}, max+1] : max }
  trail[trees]
end

Test

bamboos_1 = [ [0, 0],
              [0, 0] ]
expect(max_trail(bamboos_1)).to eq 1

bamboos_2 = [ [ 1, 6, 7],
              [ 2, 5, 8],
              [ 3, 4, 9] ] 
expect(max_trail(bamboos_2)).to eq 9 

bamboos_3 = [ [14, 9,12,10],
              [ 1,11, 5, 4],
              [ 7,15, 2,13],
              [ 6, 3,16, 8] ]            
expect(max_trail(bamboos_3)).to eq 4

2016/06/05 22:56

rk

from multiprocessing import Pool
from random import randint
import os, sys

c = os.cpu_count()
sys.setrecursionlimit(2**13)

data = list(list(int(i) for i in j.split())for j in '''14 9 12 10
1 11 5 4
7 15 2 13
6 3 16 8'''.split('\n'))


#N = 52
#data = list(list(randint(1, 100) for i in range(N)) for j in range(N))

class block(object):
    def __init__(self, N):
        self.N = N; self.l, self.r, self.u, self.d = [None]*4
    def move_lower(self):
        return list((x for x in (self.u, self.d, self.l, self.r) if x != None and x.N < self.N))
    def move_lower_chain(self, res = [], history = []):
        return (lambda temp: (res.append(history + [self.N]) if len(temp) == 0 else list(x.move_lower_chain(res, history + [x.N]) for x in temp), res)[1])(self.move_lower())

def setmap(li):
    res, n = [], len(li)
    for j in range(n):
        res.append([])
        for i in range(n):
            res[j].append(block(li[j][i]))
            if i > 0: res[j][i-1].r, res[j][i].l = res[j][i], res[j][i-1]
            if j > 0: res[j-1][i].d, res[j][i].u = res[j][i], res[j-1][i]
    temp, res = res[:], []
    return sorted((lambda temp, res: (list(list((res.append(i)) for i in j) for j in temp), res)[1])(temp, res), key = lambda x: x.N)[::-1]
def proc(m, number, cores):
    res = []
    for i in range(number, len(m), cores):
        res.append(max(map(len, m[i].move_lower_chain())))
        if max(res) > len(m)-(i+1): break
    return res
def check(m):
    with Pool() as p:
        temp = p.starmap(proc, ((m, number, c) for number in range(c)))
    return max((lambda res: (list(list(res.append(y) for y in x) for x in temp), res)[1])([]))

if __name__ == '__main__':
    m = setmap(data)
    print(check(m))

재귀함수 제한 늘려도 52가 한계네요. 52 기준 1초 미만으로 나옵니다. 파이썬 3.5.1

2016/06/27 00:32

Flair Sizz

C 언어 입니다. 입력받은 배열 N x N 과 가장긴거리를가지는 값을 가질 배열 N x N 배열의 크기를 넘어가지 않으면서 현재의 (j, i) 보다 큰값을 찾아나가면서 1씩 증가시켜줍니다. LIS를 을 만족시키고싶었는데 재귀형식으로 된거같네요 DP도 만족시키고싶어서 최대거리를 미리 구해놨으면 그쪽방향은 배열의 값을 바로 읽게했습니다. 코드길이를 줄이면서 간단하게 하고싶은데 요령이 없네요. ㅡ.ㅜ 앞으로 더 잘하겠습니당

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<malloc.h>


int isPath(int **a, int i, int j)
{
    if (i == -1 || j == -1 || i == 4 || j == 4)
        return 0;

    return a[i][j];
}
int max(int a, int b, int c, int d)
{
    int max = a;
    if (max < b)
        max = b;
    if (max < c)
        max = c;
    if (max < d)
        max = d;
    return max;
}
int initial(int **a, int **l, int j, int i)
{   
    int left = 0, right = 0, up = 0, down = 0;
    if (a[j][i] < isPath(a, j , i + 1))
    {
        if (l[j][i + 1] == 0)
            right = initial(a, l, j, i + 1);
        else
            right = l[j][i + 1];
    }
    if (a[j][i] < isPath(a, j , i -1))
    {
        if (l[j][i - 1] == 0)
            left = initial(a, l, j , i -1);
        else
            left = l[j][i - 1];
    }
    if (a[j][i] < isPath(a, j + 1, i))
    {
        if (l[j + 1][i] == 0)
            down = initial(a, l, j + 1, i);
        else
            down = l[j + 1][i];
    }
    if (a[j][i] < isPath(a, j - 1, i))
    {
        if (l[j - 1][i] == 0)
            up = initial(a, l, j - 1, i);
        else
            up = l[j - 1][i];
    }

    return 1 + max(left, right, up, down);
}

int main()
{
    int n = 0;

    scanf("%d", &n);

    int **a;
    a = (int **)malloc(sizeof(int*) * n);
    for (int i = 0; i < n; i++)
        a[i] = (int*)malloc(sizeof(int) * n);

    for (int j = 0; j < n; j++)
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i][j]);


    int** LIS = (int**)malloc(sizeof(int*) * n);
    for (int i = 0; i < n; i++)
        LIS[i] = (int*)malloc(sizeof(int) * n);

    for (int j = 0; j < n; j++)
        for (int i = 0; i < n; i++)
            LIS[j][i] = 0;
    for (int j = 0; j < n; j++)
    {
        for (int i = 0; i < n; i++)
        {
            LIS[j][i] = initial(a, LIS, j, i);
        }
    }

    for (int j = 0; j < n; j++)
    {
        for (int i = 0; i < n; i++)
            printf("%d ", LIS[j][i]);
        printf("\n");
    }


}

2016/07/03 23:43

양 상호

Delphi 2010 DP(Dynamic Program방식) 사용

type
  TArrayInt2d = array of array of Integer;

function fnGeedyPanda(const M: TArrayInt2d; RCnt, CCnt: Integer; var ci, cj: Integer): Integer;
var
  V: array of array of Integer;
  CMax, i, j: Integer;

  function fnSearchValue(A, b, minVal: Integer): Integer;
  var
    val: Integer;
  begin
    if (A < 0) or (A = RCnt) or (b < 0) or (b = CCnt) then
      exit(0);

    if V[i, j] <> -1 then
     exit(V[i, j]);
    val := M[A, b];
    if val <= minVal then
      exit(0);
    result := 1 + Max(Max(fnSearchValue(A - 1, b, val), fnSearchValue(A + 1, b, val)),
      Max(fnSearchValue(A, b - 1, val), fnSearchValue(A, b + 1, val)));
  end;

begin
  SetLength(V, RCnt, CCnt);
  for i := 0 to RCnt - 1 do
    for j := 0 to CCnt - 1 do
      V[i, j] := -1; // 초기값이 -1 
  CMax := 0;
  ci := 0;
  cj := 0;
  for i := 0 to RCnt - 1 do
    for j := 0 to CCnt - 1 do
      if V[i, j] = -1 then
      begin
        V[i, j] := fnSearchValue(i, j, -1);
        if CMax < V[i, j] then
        begin
          ci := i;
          cj := j;
          CMax := V[i, j];
        end;
      end;
  result := CMax;
end;

procedure TForm4.btn욕심쟁이판다Click(Sender: TObject);
Const
  C: array [0 .. 3, 0 .. 3] of Integer = ((14, 9, 12, 10), (1, 11, 5, 4), (7, 15, 2, 13), (6, 3, 16, 8));
var
  ci, cj, CMax: Integer;
  M: TArrayInt2d;
begin
  // Dreedy 방식
  SetLength(M, 4, 4);
  for ci := 0 to 3 do
    for cj := 0 to 3 do
      M[ci, cj] := C[ci, cj];

  CMax := fnGeedyPanda(M, 4, 4, ci, cj);
  Memo1.Lines.Add(format('욕심쟁이 판다: Pos %d (%d,%d), Count: %d', [M[ci, cj], ci + 1, cj + 1, CMax]));
end;

2016/07/08 14:19

강 경수

부족한 점이 많아서 다른분보다 코드가 길은거 같아여 test

0 0

0 0

1

1 6 7

2 5 8

3 4 9

9

14 9 12 10

1 11 5 4

7 15 2 13

6 3 16 8

4

#include <stdlib.h>
#include<stdio.h>


int getMax(int t1, int t2);
int LIS(int** f, int** k, int n, int x, int y);

void main(void) {

    int n =  0;

    scanf("%d",&n);

    int** f = (int**)malloc(sizeof(int*) * n );
    for(int i = 0; i<n ; i++) {
         f[i] = (int*)malloc(sizeof(int) * n );
    }

    for(int i = 0; i<n ; i++)
        for(int j= 0; j<n ; j++) 
            scanf("%d",&f[i][j]);


    int** k = (int**)malloc(sizeof(int*) * n );
    for(int i = 0; i<n ; i++) {
         k[i] = (int*)malloc(sizeof(int) * n );
    }
    for(int i = 0; i<n ; i++)
        for(int j= 0; j<n ; j++) 
            k[i][j] = 1;
    int max = 0;
    for(int i = 0; i<n ; i++)
        for(int j= 0; j<n ; j++) 
            max = getMax(max, LIS(f, k, n, i, j));

    printf("%d\t", max);
}

int getMax(int t1, int t2) {
    if(t1 > t2)
        return t1;
    else
        return t2;
}

int LIS(int** f, int** k, int n, int x, int y) {

    for(int i = 0; i<n ; i++) {
        for(int j= 0; j<n ; j++) {
            if(f[i][j] >= f[x][y]) {
            if(i+1 < n && f[i][j] < f[i+1][j])
                k[i+1][j] = k[i][j] + 1;
            if(j+1 < n && f[i][j] < f[i][j+1])
                k[i][j+1] = k[i][j] + 1;
            if(i-1 >= 0 && f[i][j] < f[i-1][j])
                k[i-1][j] = k[i][j] + 1;
            if(j-1 >= 0 && f[i][j] < f[i][j-1])
                k[i][j-1] = k[i][j] + 1;
            }
        }
    }

    int max = 0;
    for(int i = 0; i<n ; i++) {
        for(int j= 0; j<n ; j++) {
            if(f[i][j] >= f[x][y]) {
            if(i+1 < n && f[i][j] > f[i+1][j])
                max = getMax(max ,k[i+1][j]);
            if(j+1 < n && f[i][j] > f[i][j+1])
                max = getMax(max ,k[i][j+1]);
            if(i-1 >= 0 && f[i][j] > f[i-1][j])
                max = getMax(max ,k[i-1][j]);
            if(j-1 >= 0 && f[i][j] > f[i][j-1])
                max = getMax(max ,k[i][j-1]);
            }
            k[i][j]= max + 1;
            max = 0;
        }
    }

    for(int i = 0; i<n ; i++) {
        for(int j= 0; j<n ; j++) {
            max = getMax(max ,k[i][j]);
        }
    }
    return max;
}

2016/09/02 14:00

코딩초보

자바입니다

package study;

import java.util.Scanner;

public class panda {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int fr[][] = new int[n][n];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                fr[i][j] = sc.nextInt();
            }
        }

        int temp, answer = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                temp = solve(n, i, j, fr);
                if (answer < temp) {
                    answer = temp;
                }
            }
        }

        System.out.println(answer);

    }

    public static int solve(int n, int x, int y, int fr[][]) {
        int result = 1;
        int dir[] = { 0, 0, 0, 0 };
        if (x > 0 && fr[x][y] < fr[x - 1][y]) {
            dir[0] = solve(n, x - 1, y, fr) + 1;
        }
        if (y > 0 && fr[x][y] < fr[x][y - 1]) {
            dir[1] = solve(n, x, y - 1, fr) + 1;
        }
        if (x + 1 < n && fr[x][y] < fr[x + 1][y]) {
            dir[2] = solve(n, x + 1, y, fr) + 1;
        }
        if (y + 1 < n && fr[x][y] < fr[x][y + 1]) {
            dir[3] = solve(n, x, y + 1, fr) + 1;
        }

        for (int i = 0; i < 4; i++) {
            if (result < dir[i]) {
                result = dir[i];
            }
        }

        return result;
    }
}

어떻게 하면 더 깔끔하게 할 수 있을거 같은데 그냥 마무리

2016/09/08 17:49

JD

대나무 덕후 욕심쟁이 판다 색히

#include <stdio.h>
#define SIZE 4

enum { ROOT, L, R, T, B };

int maxDepth = 0;

void next(int a[SIZE][SIZE], int row, int col, int preDir, int preVal, int preDepth) {
    int curVal = a[row][col];
    int cond = 0;
    cond = cond || row < 0;
    cond = cond || col < 0;
    cond = cond || row > SIZE - 1;
    cond = cond || col > SIZE - 1;
    cond = cond || (preDir != ROOT && preVal >= curVal);
    if(cond) {
        if(preDepth > maxDepth)
            maxDepth = preDepth;
        return; 
    }

    int curDepth = preDepth + 1;    
    if(preDir != R) next(a, row    , col - 1, L, curVal, curDepth);
    if(preDir != L) next(a, row    , col + 1, R, curVal, curDepth);
    if(preDir != B) next(a, row - 1, col    , T, curVal, curDepth);
    if(preDir != T) next(a, row + 1, col    , B, curVal, curDepth);
}

int main() {
    int a[SIZE][SIZE] = {
                    { 14,  9, 12, 10 }, 
                    {  1, 11,  5,  4 },
                    {  7, 15,  2, 13 },
                    {  6,  3, 16,  8 }
                };

    for(int row = 0; row < SIZE; row++) {
        for(int col = 0; col < SIZE; col++) {
            next(a, row, col, ROOT, a[row][col], 0);
        }
    }
    printf("maxDepth: %d", maxDepth);   
    return 0;
}

2016/09/16 22:33

이 종성

자바입니다. 간단하게 작성하려고했는데 생각보다 길게 작성이됬네요.

public class GreedyPanda {
    private int[][] forest;
    private int size;
    private int MAX;

    private final int[] X = { 0, 1, 0, -1 };
    private final int[] Y = { 1, 0, -1, 0 };

    public GreedyPanda(int size, int[][] forest) {
        this.size = size;
        this.MAX = size * size;
        this.forest = forest;
    }

    public int getMaximumAliveDay() {
        int result = 0;
        int temp = 0;
        for (int i = 0; i < this.size; i++) {
            for (int j = 0; j < this.size; j++) {
                temp = findMaximumPath(i, j);
                result = temp > result ? temp : result;
                if (result == this.MAX) {
                    return result;
                }
            }
        }
        return result;
    }

    private int findMaximumPath(int x, int y) {
        int result =1;
        int nextX, nextY, temp;

        for (int i = 0; i < 4; i++) {
            temp = 0;
            nextX = x + X[i];
            nextY = y + Y[i];

            if (inForest(nextX, nextY) && forest[x][y] < forest[nextX][nextY]) {
                if ((temp = findMaximumPath(nextX, nextY)+1) > result) {
                    result = temp;
                }
            }
        }
        return result;
    }

    private boolean inForest(int x, int y) {
        return (x >= 0 && x < size && y >= 0 && y < size);
    }
}

2016/10/07 16:53

한인규(Hayden)

Ruby

def max_trail(bamboos, n=[*0...bamboos.size])
  trees = n.product(n).map {|x,y| [y,x,bamboos[x][y]] }
  nexts = ->x,y,v { trees.select {|ex,ey,ev| (x-ex).abs+(y-ey).abs <2 && ev>v } }
  trail = ->xy,cnt=1,t=nexts[*xy] { t[0]? t.map {|e| trail[e,cnt+1] } : cnt }
  trees.map(&trail).flatten.max
end


Test
bamboos_1 = [ [0, 0],
              [0, 0] ]
expect(max_trail(bamboos_1)).to eq 1

bamboos_2 = [ [ 1, 6, 7],
              [ 2, 5, 8],
              [ 3, 4, 9] ] 
expect(max_trail(bamboos_2)).to eq 9 

bamboos_3 = [ [14, 9,12,10],
              [ 1,11, 5, 4],
              [ 7,15, 2,13],
              [ 6, 3,16, 8] ]            
expect(max_trail(bamboos_3)).to eq 4

2016/10/09 18:18

박 동민

#include<iostream>
#include<vector>
using namespace std;
#define FSIZE 4
int arr[FSIZE][FSIZE] = { { 14, 9, 12, 10 },{ 1, 11, 5, 4 },{ 7, 15, 2, 13 },{ 6, 3, 16, 8 } };
int xRot[4] = { 0, 1, 0, -1 };
int yRot[4] = { 1, 0, -1, 0 };

int findPath(int _x, int _y, vector<int> v);
int main()
{
    vector<int> vvv;
    int pSuvDate = 0;
    int cSuvDate = 0;

    for (int i = 0; i < FSIZE; i++)
    {
        for (int j = 0; j < FSIZE; j++)
        {
            cout << arr[i][j] << " : ";
            vvv.push_back(arr[i][j]);
            cSuvDate = findPath(i, j, vvv);
            if (pSuvDate < cSuvDate)
                pSuvDate = cSuvDate;
            vvv.clear();
            cout << endl;

        }
    }
    cout << "result" << pSuvDate << endl;
    return 0;
}
int findPath(int _x, int _y, vector<int> v)
{
    vector<int>  vvv = v;
    int suvDate[4] = { 1, 1, 1, 1 };
    bool isEnd = true;
    for (int i = 0; i < 4; i++)
    {
        if (0 <= _y + yRot[i] && _y + yRot[i] <= FSIZE-1 && 0 <= _x + xRot[i] && _x + xRot[i] <= FSIZE-1)
        {
            if (arr[_x][_y] < arr[_x + xRot[i]][_y + yRot[i]])
            {
                vvv.push_back(arr[_x + xRot[i]][_y + yRot[i]]);
                suvDate[i] += findPath(_x + xRot[i], _y + yRot[i], vvv);
                isEnd = false;
                vvv.pop_back();
            }
        }
    }
    int a = 0;
    if (isEnd)
    {
        cout << endl;
        for (int i = 0; i < vvv.size(); i++)
            cout << "=" << vvv[i];
    }
    for (int i = 0; i < 4; i++)
    {
        if (suvDate[a] <= suvDate[i])
            a = i;
    }
    return suvDate[a];
}

2016/11/02 19:37

이 재화

시작점부터 더 큰 값이 있는 칸으로 옮겨갈 수 있는 최대 길이..

일단 main()부터..

int main(int argc, const char * argv[]) {
    int area[] = {
        14,9,12,10,
        1,11,5,4,
        7,15,2,13,
        6,3,16,8
    };
    int days = howLongWillPandaLive(area, 4);
    printf("%d\n", days);
    return 0;
}

쉽게 접근하면 각 지점에서 모두 최대로 살수있는 날을 구해서 그 중의 가장 큰값을 구하면 될듯.

int howLongWillPandaLive(int area[], int n) {
    int max = 0;
    for (int i=0; i<n; i++) {
        for (int j=0; j<n; j++) {
            int days = howLong(area, n, i, j);
            if (max < days) {
                max = days;
            }
        }
    }
    return max;
}

시작점으로부터 가장 오래 살 수 있는 날은.. 재귀적으로 모든 가능한 방향으로 갈 수 있는 만큼.. 마치 depth first search 같네요. 일단 재귀로 풀어봅니다.

int howLong(int area[], int n, int r, int c) {
    int days = 1;
    int current = area[r*n + c];

    // 더 많은 쪽으로 옮겨갈 수 있다.
    if (r > 0 && area[(r-1)*n + c] > current) days = max(days, 1+howLong(area, n, r-1, c));
    if (c > 0 && area[r*n + (c-1)] > current) days = max(days, 1+howLong(area, n, r, c-1));
    if (r+1 < n && area[(r+1)*n + c] > current) days = max(days, 1+howLong(area, n, r+1, c));
    if (c+1 < n && area[r*n + (c+1)] > current) days = max(days, 1+howLong(area, n, r, c+1));

    return days;
}

끝!

그런데 howLong이 너무 많이 불리는 문제가.. 그 값은 늘 같음 (그 점에서 시작해서 가장 오래 살수 있는 날) 그럼 기억해두기 (memoization)

int howLongWillPandaLive(int area[], int n) {
    int *memo = (int*)calloc(n*n, sizeof(int));

    int max = 0;
    for (int i=0; i<n; i++) {
        for (int j=0; j<n; j++) {
            int days = howLong(area, n, i, j, memo);
            if (max < days) {
                max = days;
            }
        }
    }
    free(memo);
    return max;
}

howLong()memo에 이미 값이 있으면 그 값을 바로 반환하고 아니면 계산해서 기억해두기

int howLong(int area[], int n, int r, int c, int memo[]) {
    int days = 1;
    int current = area[r*n + c];

    if (memo[r*n + c] > 0) return memo[r*n + c];

    // 더 많은 쪽으로 옮겨갈 수 있다.
    if (r > 0 && area[(r-1)*n + c] > current) days = max(days, 1+howLong(area, n, r-1, c, memo));
    if (c > 0 && area[r*n + (c-1)] > current) days = max(days, 1+howLong(area, n, r, c-1, memo));
    if (r+1 < n && area[(r+1)*n + c] > current) days = max(days, 1+howLong(area, n, r+1, c, memo));
    if (c+1 < n && area[r*n + (c+1)] > current) days = max(days, 1+howLong(area, n, r, c+1, memo));

    memo[r*n + c] = days;
    return days;
}

2016/11/05 14:21

Han Jooyung

c++ 재귀로 풀어봤습니다.

#include<iostream>

using namespace std;

int maxDay = 0;

void find(int i, int j, int n, int input[4][4], int day)
{
    if(maxDay < day)
        maxDay = day;

    day++;

    if(i > 0 && input[i-1][j] > input[i][j]) //up
        find(i-1,j,n,input,day);

    if(i < n-1 && input[i+1][j] > input[i][j]) //down
        find(i+1,j,n,input,day);

    if(j > 0 && input[i][j-1] > input[i][j]) //left
        find(i,j-1,n,input,day);

    if( j < n-1 && input[i][j+1] > input[i][j]) //right
        find(i,j+1,n,input,day);

    return;
}

void main()
{
    cout<<"Hello Stranger!!?"<<endl;

    int input[4][4] = { 14,9,12,10, 1,11,5,4, 7,15,2,13, 6,3,16,8 };

    for(int i=0; i<4; i++)
    {
        int day = 1;

        for(int j=0; j<4; j++)
            find(i,j,4,input,day);
    }

    cout<<maxDay;

}


2016/11/10 02:35

이재웅

def greedyPanda(n,bamboo,i,j):
    max_cnt = 1 
    if bamboo.dirlst[i][j] != '0000':
        for a,b in enumerate(bamboo.dirlst[i][j]):
            cnt = 1
            if b != '1':
                continue
            if a == 0:
                cnt = greedyPanda(n,bamboo,i-1,j) + 1
            if a == 1:
                cnt = greedyPanda(n,bamboo,i,j+1) + 1
            if a == 2:
                cnt = greedyPanda(n,bamboo,i+1,j) + 1
            if a == 3:
                cnt = greedyPanda(n,bamboo,i,j-1) + 1
            if cnt > max_cnt:
                max_cnt = cnt
    return max_cnt

class Bamboo_g:
    def __init__(self,n,lst):
        self.n = n
        self.lst = [[None for j in range(self.n)] for i in range(self.n)]
        for i in range(self.n):
            for j in range(self.n):
                self.lst[i][j] = int(lst[i][j])
        self.dirlst = self.createDirect(lst)

    def createDirect(self,lst):
        dir_lst = [[None for j in range(self.n)] for i in range(self.n)]
        for i in range(self.n):
            for j in range(self.n):
                num = 0
                add_zero = ''
                if i > 0:
                    if self.lst[i-1][j] > self.lst[i][j]:
                        num += 8
                if i < n-1:
                    if self.lst[i+1][j] > self.lst[i][j]:
                        num += 2
                if j > 0:
                    if self.lst[i][j-1] > self.lst[i][j]:
                        num += 1
                if j < n-1:
                    if self.lst[i][j+1] > self.lst[i][j]:
                        num += 4
                if num < 2:
                    add_zero += '0'
                if num < 4:
                    add_zero += '0'
                if num < 8:
                    add_zero += '0'
                dir_lst[i][j] = add_zero+bin(num)[2:]
        return dir_lst

n = int(input(':'))
lst = [[None for j in range(n)] for i in range(n)]

for i in range(n):
    tmp_line = input().split(' ')
    for j in range(n):
        lst[i][j] = tmp_line[j]

b = Bamboo_g(n,lst)

max_cnt = 0
for i in range(n):
    for j in range(n):
        cnt = greedyPanda(n,b,i,j)
        max_cnt = max(max_cnt,cnt)
print(max_cnt)

n*n 크기의 방향리스트를 만들어서 리스트를 참조하며 재귀적으로 함수를 호출합니다.

2016/11/26 13:52

바바

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Panda {

    static int n;
    static int m;
    static int[][] a;

    public static void main(String[] args) throws FileNotFoundException {
        String path = Panda.class.getResource("").getPath();
        Scanner sc = new Scanner(new File(path + "Panda.txt"));
        n = sc.nextInt();
        a = new int[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                a[i][j] = sc.nextInt();
            }
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                recursive(i, j, a[i][j], 0);
            }
        }

        System.out.println(m);
    }


    private static void recursive(int y, int x, int s, int c) {
        //좌
        System.out.print(s);
        if (x > 0 && s < a[y][x - 1]) {
            c = c + 1;
            recursive(y, x - 1, a[y][x - 1], c);
        }
        //상
        if (y > 0 && s < a[y - 1][x]) {
            c = c + 1;
            recursive(y - 1, x, a[y - 1][x], c);
        }
        //우
        if (x < n - 1 && s < a[y][x + 1]) {
            c = c + 1;
            recursive(y, x + 1, a[y][x + 1], c);
        }
        //하
        if (y < (n - 1) && s < a[y + 1][x]) {
            c = c + 1;
            recursive(y + 1, x, a[y + 1][x], c);
        }

        if (m < c) {
            m = c;
        }
    }
}

2017/04/03 13:46

genius.choi

def LIS(i, j):
    global life
    if life[i][j] >= 0:
        return life[i][j]

    M = 0
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        k, l = i + dx, j + dy
        if 0 <= k < N and 0 <= l < N and bamboo[k][l] > bamboo[i][j]:
                M = max(M, LIS(k, l))

    life[i][j] = M + 1
    return life[i][j]


N = 4
bamboo = [[14, 9, 12, 10], [1, 11, 5, 4], [7, 15, 2, 13], [6, 3, 16, 8]]
life = [[-1 for y in bamboo[0]] for x in bamboo]

M = 0
for i in range(N):
    for j in range(N):
        M = max(M, LIS(i, j))

print(M)

2017/08/20 23:04

Noname

haskell

import Data.Array
import Data.Function
import Data.Function.Memoize

solution :: Array (Int, Int) Int -> Int
solution arr = maximum $ flip fmap (indices arr) $ memoFix $
    \r x -> 1 + foldr max 0 (r <$> filter (on (<) (arr!) x) (nbrs x))
    where nbrs (a,b) = filter (inRange . bounds $ arr) [(a+1,b),(a-1,b),(a,b+1),(a,b-1)]

main = print $ solution $ listArray ((0,0), (3,3)) [14,9,12,10,1,11,5,4,7,15,2,13,6,3,16,8]

2017/12/24 23:03

sodii

아이디어 : 항상 자기 자신보다 큰 수로 이동하기 때문에 자기 자신에 돌아오는 길은 없다. 따로 DP를 사용할 필요가 없고, max 값만 구하면 되기 때문에 n*n 개 각각의 경로의 수를 카운트해서 그 중 가장 긴 경로를 출력한다.

def panda(arr:Array[Array[Int]]):Int = {
      val direction = List((1, 0), (0, 1), (-1, 0), (0, -1))

      def countPath(x: Int, y: Int, cnt: Int):Int = {
        if(x >= 0 && y >= 0 && x < arr.length && y < arr.length){
          var maxCnt = cnt
          for((a, b) <- direction){
            if(x + a >= 0 && y + b >= 0 && x + a < arr.length && y + b < arr.length && arr(x + a)(y + b) > arr(x)(y)){
              maxCnt = Math.max(maxCnt, countPath(x + a, y + b, cnt + 1))
            }
          }
          maxCnt
        }
        else {
          cnt
        }
      }

      var max = 0
      for(i <- 0 until arr.length; j <- 0 until arr.length){
        max = Math.max(max, countPath(i, j, 1))
      }
      max
    }
    println(panda(
      Array(
        Array(14 ,9, 12 ,10),
        Array(1 ,11, 5 ,4),
        Array(7 ,15, 2 ,13),
        Array(6 ,3, 16 ,8)
      )
    ))

2018/05/16 20:18

한강희

단순 recurison

def panda(mat,x,y):
    dr = ( (1,0),(-1,0),(0,1),(0,-1) )

    nib = []
    for dx,dy in dr:
        if 0<=x+dx<len(mat) and 0<=y+dy<len(mat[0]) and mat[x][y] < mat[x+dx][y+dy]:
            nib.append(panda(mat,x+dx,y+dy))
    if not nib: return 1
    return max(nib)+1

sample = '''\
14 9 12 10
1 11 5 4
7 15 2 13
6 3 16 8'''

board = [[*map(int,i.split())] for i in sample.split('\n')]

print(max(panda(board,i,j) for i in range(len(board)) for j in range(len(board[0]))))

메모이제이션

memo = {}
def panda(mat,x,y):
    if (x,y) in memo: return memo[(x,y)]
    dr = ( (1,0),(-1,0),(0,1),(0,-1) )

    nib = []
    for dx,dy in dr:
        if 0<=x+dx<len(mat) and 0<=y+dy<len(mat[0]) and mat[x][y] < mat[x+dx][y+dy]:
            nib.append(memo[(x+dx,y+dy)] if (x+dx,y+dy) in memo else panda(mat,x+dx,y+dy))

    if not nib: memo[(x,y)] = 1
    else: memo[(x,y)] = max(nib)+1
    return memo[(x,y)]

sample = '''\
14 9 12 10
1 11 5 4
7 15 2 13
6 3 16 8'''

board = [[*map(int,i.split())] for i in sample.split('\n')]

print(max(panda(board,i,j) for i in range(len(board)) for j in range(len(board[0]))))

2018/07/29 12:54

Creator

class Panda:
    def __init__(self, size, data):
        self.n = size
        self.d = data
        self.direc = ((1,0),(-1,0),(0,1),(0,-1))

    def max_depth(self, x, y):
        c = self.d[(x,y)]
        temp = []
        for dx, dy in self.direc:
            nx = x + dx
            ny = y + dy
            if 0<=nx<self.n and 0<=ny<self.n:
                if self.d[(nx,ny)] > c:
                    temp.append(self.max_depth(nx,ny))
        if temp:
            return 1 + max(temp)
        else:
            return 1

    def find_max_life(self):
        ans = 0
        for x in range(self.n):
            for y in range(self.n):
                a = self.max_depth(x,y)
                if a > ans:
                    ans = a
        print(ans)


n = int(input())

data = {}
for y in range(n):
    line = input().split(' ')
    for x in range(n):
        data[(x,y)] = int(line[x])


P = Panda(n, data)
print('정답 :')
P.find_max_life()
4
14 9 16 10
1 11 12 4
2 15 7 13
3 5 6 8
정답 :
8

2019/04/27 11:36

messi

파이썬 3.7 사용. 출제의도와 맞는 풀이 방식인진 잘 모르겠지만 풀어봤습니다.

def isNum(S): #문자열S를 받아서 S가 자연수이면 True
    try:
        N=int(S)
        if N>=1:
            return True
        else:
            return False
    except:
        return False

class GreedyPanda:
    def __init__(self):
        self.K=1 #판다의 수명 초기값 (일)

    def get_N(self): #N 입력받기
        while(True): 
            tmp=input('N: ')
            N=int(tmp) if isNum(tmp) and int(tmp)<=500 else 0
            if N:
                self.N=N
                break
            else:
                print('1<=N<=500인 정수 N을 입력하세요\n')

    def get_bamboo(self): #장소별 대나무양 입력받기(중복없이 N**2개 자연수)
        N=self.N
        while(True): 
            print('장소별 대나무 양을 입력하세요')
            self.bamboo=[]
            bamboo_set=set(self.bamboo) #중복검사용
            i=1
            while(i<=N):
                tmp=input('{}행: '.format(i)).split(' ')
                bamboo_col=[int(x) for x in tmp if isNum(x)]
                if len(set(bamboo_col))==N:
                    bamboo_set.update(bamboo_col)
                    self.bamboo.append(bamboo_col)
                    i+=1
                else:
                    print('Error. 다시 입력하세요')
            if len(bamboo_set)!=N**2:
                print('중복된 값이 있습니다. 다시 입력하세요.\n')
            else:
                break
        return self.bamboo

    #본문
    def Panda_Life(self): #대나무량을 받고 판다의 수명 K를 반환
        self.K=1 #초기화
        self.get_N()
        self.get_bamboo()
        self.choice=[]
        self.dead_point=[]
        N=self.N
        for i,v1 in enumerate(self.bamboo):
            col=[]
            for j,v2 in enumerate(v1):
                r='' #'상하좌우'순서대로 이웃한 지역의 대나무양이 더 많으면 1, 적으면 0, 지정한 범위를 넘어가면 x
                     # ex> r='101x' 위 지역과 왼쪽 지역이 대나무양이 더 많고, 오른쪽에는 더이상 지역이 없다   
                #상
                if i==0: #위로 더 이상 이동할 지역이 존재하지 않음
                    r+='x'
                else: #위 지역에 대나무가 더 많으면 1 아니면 0
                    r+='1' if self.bamboo[i-1][j]>v2 else '0'
                #하
                if i==N-1: #아래로 더 이상 이동할 지역이 존재하지 않음
                    r+='x'
                else: #아래 지역에 대나무가 더 많으면 1 아니면 0
                    r+='1' if self.bamboo[i+1][j]>v2 else '0'
                #좌
                if j==0: #왼쪽으로 더 이상 이동할 지역이 존재하지 않음
                    r+='x'
                else: #왼쪽 지역에 대나무가 더 많으면 1 아니면 0
                    r+='1' if self.bamboo[i][j-1]>v2 else '0'
                #우
                if j==N-1: #오른쪽으로 더 이상 이동할 지역이 존재하지 않음
                    r+='x'
                else: #오른쪽 지역에 대나무가 더 많으면 1 아니면 0
                    r+='1' if self.bamboo[i][j+1]>v2 else '0'
                col.append(r)
                if '1' not in r: # 판다가 이동할 선택지가 없는 포인트. 판다는 이 포인트들에서만 죽는다.
                    self.dead_point.append([i,j]) #좌표를 저장
            self.choice.append(col)

        #판다가 죽게 될 위치에서부터 역추적하여 최장루트의 길이를 찾는다
        for p in self.dead_point:  
            self.cycle(p[0], p[1], 1) #재귀함수 호출

        print('판다의 최대수명은 {}일 입니다.'.format(self.K)) #최종 출력

    def cycle(self, i,j, days): #재귀함수. (i, j)에서 역순으로 거슬러올라간다(=0인 방향으로 추적)
        if self.choice[i][j][0]=='0': #상
            self.cycle(i-1,j,days+1)
        if self.choice[i][j][1]=='0': #하
            self.cycle(i+1,j,days+1)
        if self.choice[i][j][2]=='0': #좌
            self.cycle(i,j-1,days+1)
        if self.choice[i][j][3]=='0': #우
            self.cycle(i,j+1,days+1)
        elif days>self.K: #더 이상 갈곳이 없음(=출발점으로 돌아옴) and 최대길이(수명) 갱신
            self.K=days
            #루프 종료

if __name__=="__main__":
    a=GreedyPanda()
    a.Panda_Life()

2019/06/08 15:47

왕초보

inp="""14 9 12 10
1 11 5 4
7 15 2 13
6 3 16 8"""
inp2="""1 6 7
2 5 8
3 4 9"""
inp3="""0 0
0 0"""
lst=[ln.split(" ") for ln in inp.split("\n")]
lst2=[ln.split(" ") for ln in inp2.split("\n")]
lst3=[ln.split(" ") for ln in inp3.split("\n")]

elst=[]
sd=1
def solve(y,x,lst):
    global sd
    cn=int(lst[y][x])
    for dy,dx in [(1,0),(0,1),(-1,0),(0,-1)]:
        ny,nx=y+dy,x+dx
        if 0<=ny<len(lst) and 0<=nx<len(lst[0]):
            if int(lst[ny][nx])>cn:
                sd+=1
                solve(ny,nx,lst)
                sd-=1
    elst.append(sd)
    return elst

출력

elst=[] #elst는 매번 빈 리스트로 초기화
for y in range(len(lst)):
    for x in range(len(lst[0])):
        solve(y,x,lst)
print(max(elst)) #4

elst=[]
for y in range(len(lst2)):
    for x in range(len(lst2[0])):
        solve(y,x,lst2)
print(max(elst)) #9

elst=[]
for y in range(len(lst3)):
    for x in range(len(lst3[0])):
        solve(y,x,lst3)
print(max(elst)) #1

2020/09/20 19:52

박시원

paths = []
def findRoute(n, r, c, cnt, lst):
    dr = [-1,0,1,0]
    dc = [0,1,0,-1]
    gonext = False
    for i in range(4):
        if 0<= r+dr[i] < n and 0<= c+dc[i] < n and lst[r+dr[i]][c+dc[i]]>lst[r][c]:
            findRoute(n, r+dr[i], c+dc[i], cnt+1, lst)
            gonext = True
    if gonext == False:
        paths.append(cnt)


# n = int(input('대나무 숲의 크기 n(1<=n<=500): '))
# bambooForest = []
# for i in range(n):
#     baboos = [int(j) for j in input('%d번째 대나무 숲의 정보: ' %(i+1)).split()]
#     bambooForest.append(baboos)
n = 4
bambooForest = [[14, 9, 12, 10], [1, 11, 5, 4], [7, 15, 2, 13], [6, 3, 16, 8]]
for r in range(n):
    for c in range(n):
        findRoute(n,r,c,1, bambooForest)
print(max(paths))

2023/11/03 16:54

insperChoi

목록으로