반응형

javascript를 좋아하는 입장에서 더욱 애정이 가는 글을 쓰게 되네요. 왜 좋냐고 물어보시면 다됩니다. 이게 될까? 하면 되고 이것도? 하면 되는게 javascript이기 때문이죠. (물론 제가 아직 내공이 많이 부족해서 그럴 수도 있습니다) 또한, 프로그래밍 언어 대부분은 데이터 타입에 대해 강력하게 요구하죠. 하지만 javascirpt는 느슨한 타입 체크를 합니다. 물론 컴파일러가 오류를 찾을 수 없다는 단점으로 작용하기도 하죠. 하지만 이는 오류를 찾을 수 없지만 그만큼 자유로움을 준다는 이야기이기도 합니다! 그리고 점점 javascript가 중요시 되고 있는 이 시점에서 싫어한다면 개발자로 손해 아닐까요?? 여담은 이쯤하고 이제 본론으로 넘어가도록 하겠습니다.


모든 코드는 Atom 에디터, Chrome, Mac OS환경에서 진행하겠습니다.


자바스크립트 기본서를 읽으셨다면 다양한 문법들을 배우셨을겁니다. 저는 이중 크게 자바스크립트에서 (감히)쓸만한? 좋은! 문법들을 말해보고자 합니다.


1) 숫자

2) 문자열(string)

3) 문장(statements)

4) 표현식(Expression)

5) 리터럴

6) 함수


첫 번째는 숫자입니다. 자바스크립트에서는 정수와 실수의 구분이 없습니다. 즉 1과 1.0이 같은 값입니다. 이는 오버플로우를 피할 수 있는 편리한 특성이라고 할 수 있겠죠. 


두 번째는 문자열입니다. 자바스크립트에서는 숫자와 같이 문자 타입이 없습니다. 또한 length라는 속성도 존재하며 문자열이 한번 만들어지면 불변하는 특성도 가지고 있죠. 


세 번째는 문장입니다. case, while, if, try, throw, break등등... 이러한 기능이 없다면 언어라고 생각할 수도 없이 굉장히 유용하고 자주 사용하는 기능이죠.


--------------------------------------------------------------------------------------------------------------------------------


사실 지금까지는 뭐야? 말장난하는건가? 라고 생각하실수도 있습니다. ㅎㅎ 사실 문법에서 좋은 문법이 뭐 자주사용하고 유용하기 때문에 더 이렇게 작성할 수도 있겠네요


네 번째로는 표현식인데 이는 특히 삼항 연산자를 말씀드리고 싶네요. 현업에서도 많이 사용하고 개인적으로는 알고리즘 풀이를 할때도 자주 사용하는 연산자입니다. 자바스크립트만의 특징이라고 할 수는 없지만 굉장히 편리한 건 사실입니다. 또한 typeof, 논리연산자 등 다양한 표현식을 제공합니다.


다섯 번째는 리터럴입니다. 객체 리터럴은 새로운 객체를 생성할 때 편리한 표기법입니다. 속성명은 이름 또는 문자열로 지정할 수 있습니다. 리터럴은 고정된 값을 뜻하는데 어떠한 값을 명칭하는 것이 아니라 저장된 값 자체를 말하는 것이다. 때문에 정수 리터럴, 문자열 리터럴, 배열 리터럴 다양한 리터럴이 존재하고 불린다. 즉, 리터럴이란 상수와 마찬가지로 메모리 어딘가에 값이 변하지 않도록 저장이 되지만 그 이름은 없는 것이다. 다시 말해 컴파일시 프로그램 내에 정의되어 있는 그대로 해석되어야 하는 값이라고 할 수 있다. 자세한 내용은 따로 리터럴에 대해 다룰 예정이니 조금만 참아주세요!! ㅎㅎ 궁금하시면 개발자는 go google!


마지막으로는 함수 입니다. 이 함수도 함수 리터럴로 사용할 수 있는데 함수 리터럴은 함수값을 정의합니다. 또한 자바스크립트에서의 함수도 우리가 기존에 사용했던 언어와 굉장히 유사하다고 볼 수 있겠네요!


그럼 다음 장부터는 자바스크립트를 본격적으로 공부해보도록 하겠습니다. 

반응형
반응형

본 게시글은 Effective Java 2판을 참고하여 작성하였습니다.


생성자 인자가 많다면 코드작성 뿐만아니라 가독성도 떨어지게 될 것입니다. 보통 선택적 인자를 받는 생성자가 존재할 때는 점층적 생성자 패턴을 적용합니다. 필수 인자만 받는 생성자를 하나 정의하고, 선택적 인자를 하나씩 추가해서 작성하곤 합니다. 만약 그 선택적 인자가 10개 이상이 넘어간다면 그 많은 인자가 무슨 값인지 알기 위해서는 주의 깊게 봐야합니다. 또한 자료형이 같은 인자들이 많아진다면 클라이언트가 인자의 순서를 실수로 뒤집게 되는 경우 문제가 생기겠죠


때문에 두번째 대안으로 자바빈 패턴을 이용하곤 합니다. 인자 없는 생성자를 호출하여 객체를 생성한 다음, 설정 메서드를 호출하여 필수 필드와 선택필드까지 초기화 하는 것입니다. 하지만 1회의 함수 호출로 객체 생성을 끝낼 수 없어, 객체 일관성이 일시적으로 깨질수 있다는 단점이 존재하죠. 일관성이 깨지면 디버깅 하기도 어렵고 자바빈 패턴으로는 변경 불가능한 클래스를 만들 수 없다는 것이 가장 critical하다고 할 수 있습니다. 


그렇다면 이러한 문제점을 해결할 수 있는 방법은 무엇일까요? 바로 Builder패턴입니다. 필요한 객체를 직접 생성하는 대신, 먼저 필수 인자들을 생성자 or 정적 팩토리 메서드(1강 참조)에 전부 전달하여 빌더 객체를 만듭니다. 이후 빌더 객체에 정의된 설정 메서드들을 호출하여 선택적 인자를 추가하는 방식입니다. 마지막으로는 아무런 인자없이 build메서드를 호출하여 변경 불가능한 객체를 만듭니다. 음... 일단 그 실제 코드를 볼까요?


public class NutritionFacts {

private final int servingSize;

private final int servings;

private final int calories;

private final int fat;

private final int sodium;

private final int carbohydrate;


public static class Builder {

// 필수 인자

private final int servingSize;

private final int servings;


// 선택적 인자는 기본값으로 초기화

private int calories = 0;

private int fat = 0;

private int carbohydrate = 0;

private int sodium = 0;


public Builder(int servingSize, int servings) {

this.servingSize = servingSize;

this.servings = servings;

}


public Builder calories(int value) {

calories = value;

return this;

}


public Builder fat(int value) {

fat = value;

return this;

}


public Builder carbohydrate(int value) {

carbohydrate = value;

return this;

}


public Builder sodium(int value) {

sodium = value;

return this;

}

public NutritionFacts build() {

return new NutritionFacts(this);

}

}

private NutritionFacts(Builder builder) {

servingSize = builder.servingSize;

servings = builder.servings;

calories = builder.calories;

fat = builder.fat;

sodium = builder.sodium;

carbohydrate = builder.carbohydrate;

}

}


NutritionFacts 객체가 변경 불가능하다는 것과 모든 인자가 한곳에 모여 있다는 것을 다시 보자. 빌더에 정의된 설정 메서드는 빌더 객체 자신을 반환하기 때문에 코드는 이어서 쓸 수 있다. 사용하는 예를 보자.


NutritionFacts coke = new NutritionFacts.Builder(240,8). caloreis(100).sodium(35).carbohydrate(27).build();


어떤가?? 필자는 이 코드를 보고 아니 이 패턴을 보고 감동했다. 마치 Python과 같이 선택적 인자에 이름을 붙일 수 있는 방법과 비슷하지 않은가? 아니 실례로 현업에서 지저분한 소스 코드를 봤던 필자에게는 마치 감동일 수 밖에 없었다. 알아보기 쉽고 쓸데없는 주석도 필요없다. 마지막 build 메서드를 통해 해당 불변식이 위반되었는지 검사 할수 있으며 실제 객체의 필드를 두고 검사할 수 있다는 것도 매우 중요하다.

그리고 빌더 패턴은 유연하다. 하나의 빌더 객체로 여러 객체를 만들 수 있기 때문이다. 다른 객체를 생성해야 할 때 마다 빌더 객체의 설정 메서드를 호출하면 다음 생성 객체를 바꿀수 있으며, 어떤 필드의 값은 자동으로 채울 수도 있다!


하지만 이 역시 장점만 존재할 수는 없을 것이다.(참 아쉽다) 객체를 생성하려면 우선 빌더 객체를 생성해야 한다. 성능에서는 분명 차이가 있겠지만 실무에서는 큰 문제가 될 소지는 아니라고 판단된다. 두번째는 이 빌더 패턴을 구현하는 소스는 점층적 생성자 패턴보다 많은 코드를 요구하기 때문에 인자가 충분히 많은 상황에서 이용해야 한다.(통제하기 힘들 정도 필자는 10개 이상이라고 생각한다) 


앞 장에서 작성한 정적 팩토리 메서드도 빌더 패턴도 상황에 맞게 써야 할 것이다. 이번장에서 작성한 빌더 패턴은 인자가 많은 생성자(특히 선택적 인자)나 정적 팩토리가 필요한 클래스를 설계할 때 매우 유리할 것이다. 가독성은 편해지고 자바빈 패턴보다 안전한 것은 물론이다. 모든 상황에 맞는 패턴은 존재하지 않는다. 다양한 패턴을 익혀두고 상황에 맞는 패턴으로 구현하는 자세를 가져야 겠다.

반응형
반응형

이 글은 Effective Java를 참조하여 작성하였습니다.


클래스를 통해 객체를 만드는 방법은 생성자를 이용하는 것입니다. 하지만 public으로 선언된 정적 팩토리 메서드를 추가하는 방법으로도 객체를 생성할 수 있습니다. 여기서 말하는 정적 팩토리 메서드는 디자인패턴에 팩토리 메서드 개념과 다릅니다.


생성자 대신 정적 팩토리 메서드를 사용하는 첫 번째 장점은 생성자와는 달리 정적 팩토리 메서드에는 이름이 있다는 것입니다. 즉 이름이 있기 때문에 네이밍을 잘 한다면 사용하기 쉽고 가독성도 높아집니다. 생성자가 다양하다면 각각의 생성자 용도를 기억하기 힘들 것이고 (아니 절대로 불가능 할 것이다) API가 없다면 제대로 파악하기 힘들것입니다. 하지만 정적 팩토리 메서드에는 이름이 있으므로 이런 문제는 생기지 않기 때문에 같은 시그니처를 가지는 생성자를 여러개 정의해야 할 경우에는 생성자들을 정적 팩토리 메서드로 바꾸고 네이밍에 신경 써야 합니다.


정적 팩토리 메서드?? 그러면 그게 뭔데 ??

Object object = new Object(); 와 같은 구문을 이용해서

일반적으로 객체를 생성할 때는 생성자를 사용할 것입니다. 


Static Factory Method 는 public static method 로서 외부 클래스에서 바로 접근할 수 있는 method인것이죠. static의 개념이 없다면 static을 먼저 검색하고 오세요~!

class Human{

String name;

int age;

int height;

int weight;

//Constructor

public Human(String name, int age, int height, int weight)

{

this.name=name;

this.age=age;

this.height=height;

this.weight=weight;

}

public Human(String name, int age)

{

this.name=name;

this.age=age;

}

//Static static Factory Method

public Human allInfoHuman() {

return new Human("sw",26,179,75);

}

public static Human portionHuman() {

return new Human("sw",26);

}

}



두번째 장점은 생성자와는 달리 호출할 때마다 새로운 객체를 생성할 필요가 없다는 것입니다. 이는 경량 패턴과 유사한데 동일한 객체가 요청되는 일이 잦고, 객체 생성시 비용이 클 경우 적용하면 성능을 크게 개선시킬 수 있습니다. 사실 위 예제 소스에서도 new연산을 계속 쓰고 있습니다. 아래에 보는 예제 소스와 같이 미리 만들어둔 객체를 리턴할 수 있기 때문에 new와 같은 비용이 큰 연산의 횟수를 줄일 수 있습니다.


public static final BigInteger ZERO = new BigInteger(new int[0], 0);


private final static int MAX_CONSTANT = 16;

private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];

private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];


static {

    /* posConst에 1 ~ 16까지의 BigInteger 값을 담는다. */

    /* negConst에 -1 ~ -16까지의 BigInteger 값을 담는다. */

}


public static BigInteger valueOf(long val) {

    // 미리 만들어둔 객체를 리턴한다

    if (val == 0)

        return ZERO;

    if (val > 0 && val <= MAX_CONSTANT)

        return posConst[(int) val];

    else if (val < 0 && val >= -MAX_CONSTANT)

        return negConst[(int) -val];


    // 새로운 객체를 만들어 리턴한다

    return new BigInteger(val);

}



세번째 장점은 생성자와 달리 반환값 자료형의 하위 자료형 객체를 반환할 수 있다는 것입니다. 즉 반환되는 객체의 클래스를 훨씬 유연하게 결정할 수 있는 것이죠. 음.. 생성자는 리턴값이 없는데 정적 팩토리 메서드는 메서드입니다. 메서드라는 이름이 붙여진 이유에 대해 잠시 생각해 보면 리턴값이 있다는 것이고, 그 리턴값이 생성자처럼 자기 자신만이 아닌 하위 객체도 리턴할 수 있다는 뜻입니다. 


 package effectiveJava;


public class Regulation {

public static void main() {

Human h = Human.setSexInstance("man");

h.getInfo();

}

}


abstract class Human {

String name;

public abstract void getInfo();


public static Human setSexInstance(String sex) {

if (sex == "man")

return new Man();

else

return new Woman();

}

}


class Man extends Human {

public void getInfo() {

System.out.println("I'm man");

}

}


class Woman extends Human {

public void getInfo() {

System.out.println("I'm woman");

}

}


마지막 장점은 형인자 자료형 객체를 만들 때 편리하다는 것입니다. 이부분은 JDK1.7이후부터는 의미가 없을 듯 하네요


Map<String, List<String>> map = new HashMap<String, List<String>>();

이와 같은 소스를

public static <K,V> HashMap<K,V> newInstance() {

       return new HashMap<K,V>();

}

와 같은 메서드가 있으면 

Map<String, List<String>> map = HashMap.newInstance()와 같이 줄여서 사용할 수 있다는 것인데 JDK1.7부터는


Map<String, List<String>> map = new HashMap<>();을 지원하니까 말이죠


지금까지 장점에 대해 알아보았는데요 장점이 있다면 단점도 역시 존재합니다.


첫번째 단점은 critical하다고 생각되는데 정적 팩토리 메서드만 있는 클래스를 만든다면 public, protected로 선언된 생성자가 없기 때문에 하위 클래스를 만들 수 없다는 것입니다. 예시로 자바 컬렉션 프레임워크에 포함된 기본 구현 클래스들의 하위 클래스는 만들 수 없다는 예시가 있네요!


두번째 단점은 정적 팩토리 메서드가 다른 정적 메서드와 확실하게 구분되지 않는다는 것입니다. 물론 API문서를 본다면 생성자와 다른 메서드는 뚜렷하게 구별되지만 정적 팩토리 메서드는 그렇지 않습니다. 때문에 더더욱 메서드 네이밍을 잘해야 겠죠.


하지만 정적 팩토리 메서드가 주는 장점은 분명 있으며, 생성자와 용도가 같다고 생각하면 큰 오산입니다. 그 차이와 장단점을 이해해서 정적 팩토리 메서드가 효과적인 경우 고려해보고 무조건적으로 public 생성자를 만드는 것을 삼가해야 합니다.


반응형
반응형

문제 링크

https://algospot.com/judge/problem/read/PI


핵심은

 

길이 3일때 난이도 + 나머지 수열 최적해

길이 4일때 난이도 + 나머지 수열 최적해

길이 5일때 난이도 + 나머지 수열 최적해


를 구하는 것인데 이때!

나머지 수열의 최적해를 구할때는 어떻게 나눴는지 중요하지 않다는 것입니다. 


어떤 자릿수 n부터 외우기 시작한다고 가정한다면

{n, n+1, n+2}

{n, n+1, n+2, n+3}

{n, n+1, n+2, n+3, n+4} 의 난이도를 구한 이후 최솟값을 사용하는 것입니다.


 //

//  main.cpp

//  AlgorihmStudy

//

//  Created by sw on 2018. 9. 19..

//  Copyright © 2018년 sw. All rights reserved.

//

#include <cstdio>

#include <string.h>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

#include <stack>

#include <vector>

#include <functional>

const int INF = 987654321;

using namespace std;


string input;

int dp[10002];


int getLevel(int head, int tail)

{

    string temp=input.substr(head,tail-head+1);

    // 모든 숫자가 같은 경우

    if(temp == string(temp.size(), temp[0]))

        return 1;

    // 숫자가 1씩 단조 증가 || 단조 감소

    bool isProgress=true;

    for(int i=0;i<temp.size()-1;i++)

    {

        if(temp[i+1]-temp[i] != temp[1]-temp[0])

            isProgress=false;

    }

    if(isProgress && abs(temp[1]-temp[0])==1)

        return 2;

    // 두 개의 숫자가 번갈아나타남

    bool isRotate=true;

    for(int i=0;i<temp.size();i++)

    {

        if(temp[i] != temp[i%2])

            isRotate=false;

    }

    if(isRotate)

        return 4;

    // 등차 수열

    if(isProgress)

        return 5;

    // 이외의 모든 경우

    return 10;

}


int solve(int start)

{

    // 기저사례

    if(start == input.size())

        return 0;

    int& ret=dp[start];

    if(ret != -1)

        return ret;

    

    ret=INF;

    

    for(int i=3; i<=5; i++)

    {

        if(start+i <= input.size())

            ret=min(ret,solve(start+i) + getLevel(start, start+i-1));

    }

    return ret;

}


int main(int argc, const char * argv[]) {

    int tc;

    scanf("%d",&tc);

    //기저 사례

    if(tc<0 || tc>51)

        exit(-1);

    while(tc--)

    {

        memset(dp,-1,sizeof(dp));

        cin>>input;

        cout<<solve(0)<<endl<<endl;

    }

    return 0;

}


반응형
반응형

문제 링크 :  https://algospot.com/judge/problem/read/TRIANGLEPATH

동적계획법을 이용하여 풀이하였습니다. dp를 처음접하는데 좋은 문제라 생각되네요


#include <cstdio>

#include <iostream>

#include <algorithm>

#include <string.h>

#include <stack>

#include <queue>

#include <vector>

#include <functional>


#define MAX 100

#define INF 0x7fffffff


using namespace std;

int n, t[MAX][MAX];

int dp[MAX][MAX];


int solve(int y, int x)

{

if(y==n-1)

return t[y][x];

int& ret=dp[y][x];

if(ret != -1)

return ret;

return ret = max(solve(y+1,x), solve(y+1,x+1)) + t[y][x];

}

int main(void)

{

int height;

scanf("%d",&n);

while(n--)

{

memset(dp,-1,sizeof(dp));

scanf("%d",&height);

for(int i=0;i<height;i++)

for(int j=0;j<i+1;j++)

scanf("%d",&t[i][j]);

cout<<solve(0,0)<<endl;

}

return 0;

}


반응형
반응형

문제 : https://www.acmicpc.net/problem/2698



아직 내공이 부족해서 한참 고민하고 겨우겨우 풀이한 문제였다.

핵심은 끝자리가 0일때와 1일때를 나누어 생각하는 것이고 n번째를 구하기 위해 n-1번째 값을 사용하기 위해 생각해 본 결과 점화식을 얻을 수 있었다. 또 점화식을 얻는데 중요한 힌트가 되었던 것은 문제 내에 식이 써있는 것도 많은 도움이 되었다.


dp[n][k][0] = dp[n-1][k][0] + dp[n-1][k][1]

dp[n][k][1] = dp[n-1][k][0] + dp[n-1][k-1][1]


소스코드

 //

//  main.cpp

//  Algorihm

//

//  Created by sw on 2018. 9. 10..

//  Copyright © 2018년 sw. All rights reserved.

//

#include <cstdio>

#include <string.h>

#include <iostream>

#include <algorithm>

#include <queue>

#define MAX 101

using namespace std;

int n,k;

int dp[MAX][MAX][2];

queue<int> q;

void solve(int n, int k){

    dp[1][0][0]=dp[1][0][1]=1;

    for(int i=2;i<=n;i++){

        for(int j=0;j<i;j++){

            dp[i][j][0] = dp[i-1][j][0]+dp[i-1][j][1];

            dp[i][j][1] = dp[i-1][j][0]+dp[i-1][j-1][1];

        }

    }

    q.push(dp[n][k][0]+dp[n][k][1]);

}

int main(int argc, const char * argv[]) {

    int tc;

    scanf("%d",&tc);

    while(tc--){

        scanf("%d %d", &n, &k);

        memset(dp,0,sizeof(dp));

        solve(n,k);

    }

    //출력

    while(!q.empty()){

        cout<<q.front()<<endl;

        q.pop();

    }

    return 0;

}


반응형

'Algorithm' 카테고리의 다른 글

[Algospot] PI 원주율 외우기  (0) 2018.09.19
[Algospot] TRIANGLEPATH 삼각형 위의 최대 경로  (0) 2018.09.17
[BOJ 2167] 2차원배열의 합 구하기  (0) 2018.09.07
[BOJ 11048] 다리놓기  (0) 2018.09.07
코딩인터뷰  (0) 2018.08.10
반응형

다형성


OOP에서의 다형성은 여러 가지 형태를 가질 수 있는 능력을 말하며, 자바에서는

한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함으로써 다형성을 프로그램적으로 구현했다.


즉 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 했다는 것이다.


class Home{

  String address;

  boolean isVisit;

  

  void rest();

  void eat(); 

}

class Room extends Home{

  String roomName;

  

  void sleep();

}


Home 과 Room은 서로 상속관계에 있으며 다음과 같이 사용할 수 있다.

Home home = new Room();

Room room = new Room();


이 코드에서 Room인스턴스 2개를 생성하고 참조변수 home,room이 생성된 인스턴스를 하나씩 참조하도록 했다.

이 경우 인스턴스가 Room타입이여도 참조변수 home은 room의 모든 멤버를 사용할 수 없다. 즉, 둘 다 같은 타입의 인스턴스지만 참조변수의

타입에 따라 사용할 수 있는 멤버의 갯수가 달라지는 것이다. 


반대로 Room r = new Home()은 불가능하다. 왜냐하면 실제 인스턴스 r이 사용할수 있는 멤버 갯수가 실제 인스턴스인 Home의 갯수보다 더 많기 때문이다.

참조변수가 사용할 수 있는 멤버의 개수는 인스턴스의 멤버 개수보다 같거나 적어야 하는 것이다. 왜냐하면 클래스는 상속을 통해 확장되는 것이지

축소될 수는 없기 때문이다. 조상 인스턴스의 멤버 개수는 자손 인스턴스의 멤버 개수보다 항상 적거나 같기 때문에 반대의 경우는 불가하다.


그렇다면 어차피 조상타입으로 선언하면 조상타입의 멤버만 참조가능할텐데 왜 일부 멤버만을 사용하도록 하는 것일까??


그 이유는 참조변수도 상속관계에 있는 클래스 사이에서는 형변환이 가능하기 때문이다. 자손타입의 변수를 조상타입으로 조상타입의 변수를 자손타입으로 변환할 수 있다.

따라서 모든 객체는 Object클래스 타입으로 형 변환이 가능하다.


형 변환에서 자손 -> 조상을 Up-casting

           조상 -> 자손을 Down-casting 이라고 하며 up은 생략이 가능하지만 down-casting은 형변환 생략이 불가하다.


그 이유는 조상타입 참조변수가 참조하는 것은 조상타입이거나 자손타입일 것이다. 즉 참조변수가 다룰 수 있는 멤버의 개수가 실제 인스턴스가 가지고 있는 멤버 개수보다 적을 것이 분명하므로 문제가 되지 않기 때문이다.

반응형
반응형

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



#include <iostream>

#define MAX 301

int N,M,K;

int dp[MAX][MAX];


using namespace std;

void getSum(){

int value;

cin>>N>>M;

for(int i=1;i<=N;i++){

for(int j=1;j<=M;j++){

cin>>value;

dp[i][j]=value + dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1];

}

}

cin>>K;

while(K--){

int x1,y1,x2,y2;

cin>>x1>>y1>>x2>>y2;

cout<<dp[x2][y2] -(dp[x1-1][y2] + dp[x2][y1-1] - dp[x1-1][y1-1])<<endl;

}

}

int main(){

getSum();

return 0;


차근차근 생각하면 어렵지 않은 문제 

어렵다면 그림을 그려보자

dp[i][j]를 구할때 중복되는 값이 있다는 것을 인지한다면 쉽게 풀 수 있다.

반응형

'Algorithm' 카테고리의 다른 글

[Algospot] TRIANGLEPATH 삼각형 위의 최대 경로  (0) 2018.09.17
[BOJ 2698] 인접한 비트의 개수  (0) 2018.09.10
[BOJ 11048] 다리놓기  (0) 2018.09.07
코딩인터뷰  (0) 2018.08.10
깊이 우선 탐색(DFS, Depth First Search)  (0) 2018.08.08
반응형

문제

준규는 N×M 크기의 미로에 갇혀있다. 미로는 1×1크기의 방으로 나누어져 있고, 각 방에는 사탕이 놓여져 있다. 미로의 가장 왼쪽 윗 방은 (1, 1)이고, 가장 오른쪽 아랫 방은 (N, M)이다.

준규는 현재 (1, 1)에 있고, (N, M)으로 이동하려고 한다. 준규가 (r, c)에 있으면, (r+1, c), (r, c+1), (r+1, c+1)로 이동할 수 있고, 각 방을 방문할 때마다 방에 놓여져있는 사탕을 모두 가져갈 수 있다. 또, 미로 밖으로 나갈 수는 없다.

준규가 (N, M)으로 이동할 때, 가져올 수 있는 사탕 개수의 최대값을 구하시오.

입력

첫째 줄에 미로의 크기 N, M이 주어진다. (1 ≤ N, M ≤ 1,000)

둘째 줄부터 N개 줄에는 총 M개의 숫자가 주어지며, r번째 줄의 c번째 수는 (r, c)에 놓여져 있는 사탕의 개수이다. 사탕의 개수는 0보다 크거나 같고, 100보다 작거나 같다.

출력

첫째 줄에 준규가 (N, M)으로 이동할 때, 가져올 수 있는 사탕 개수를 출력한다.

예제 입력 1 

3 4
1 2 3 4
0 0 0 5
9 8 7 6

예제 출력 1 

31

예제 입력 2 

3 3
1 0 0
0 1 0
0 0 1

예제 출력 2 

3

예제 입력 3 

4 3
1 2 3
6 5 4
7 8 9
12 11 10

예제 출력 3 

47







문제는 간단하다. 기본적인 DP문제이다. 유의할 점은 dp[i][j]를 구할때 대각선으로 가는 것은 고려하지 않아도 된다는 것이다. 왜냐하면 음수값을 입력하지 않기 때문이다. 즉 점화식을 구하면

dp[i][j]=max(dp[i-1][j],dp[i][j-1])+d[i][j]가 된다. 


 //

//  main.cpp

//  Algorihm

//

//  Created by sw on 2018. 9. 7..

//  Copyright © 2018년 sw. All rights reserved.

//


#include <iostream>

#include <algorithm>

#define MAX 1001

int N,M;

int dp[MAX][MAX];


using namespace std;


int move(int x, int y){

    int value;

    for(int i=1;i<=N;i++){

        for(int j=1;j<=M;j++){

            cin>>value;

            dp[i][j]=max(dp[i-1][j],dp[i][j-1])+value;

        }

    }

    return dp[x][y];

}

int main(int argc, const char * argv[]) {

    cin>>N>>M;

    cout<<move(N,M)<<endl;

    return 0;

}


반응형

'Algorithm' 카테고리의 다른 글

[BOJ 2698] 인접한 비트의 개수  (0) 2018.09.10
[BOJ 2167] 2차원배열의 합 구하기  (0) 2018.09.07
코딩인터뷰  (0) 2018.08.10
깊이 우선 탐색(DFS, Depth First Search)  (0) 2018.08.08
[백준 9507] Generations of Tribbles  (0) 2018.06.26
반응형

객체 지향의 4대 특성

캡 - 캡슐화 : 정보 은닉

상 - 상속 : 재사용 

추 - 추상화 : 모델링

다 - 다형성 : 사용 편의

객체 지향에서 Inheritance 즉 상속은 가장 중요하고 강력한 특성임은 분명하다.

지금까지 객체지향을 한번쯤이라도 공부한 사람이라면 클래스와 객체의 관계를 붕어빵틀과 붕어빵 이라는 비유를 많이 봤을 것이다. 하지만 이 비유가 적절한 지 생각해보자(이러한 개념을 일단 버려라!)


클래스 객체명 = new 클래스();

일반적 객체를 생성하는 문법이다 이 문법을 붕어빵틀과 붕어빵에 적용시켜 보자

붕어빵틀 붕어빵 = new 붕어빵틀();

!!!! 위 논리가 맞다고 생각되는가? 붕어빵틀을 생산하는 기계가 있다고 하자. 그럼 붕어빵틀이 붕어빵을 찍어내서 클래스라고 한다면! 같은 논리로 기계는 붕어빵틀을 찍어내는 클래스가 된다.

기계 붕어빵틀 = new 기계(); => 새로운 기계를 만들었는데 붕어빵틀이 되었다.


붕어빵틀은 붕어빵을 만드는 팩토리일 뿐이였던 것이다. 


클래스는 분류에 대한 개념이지 실체가 아니다. 하지만 객체는 실체다.


추상화 : 모델링

공통되는 특성이나 속성 따위를 추출하여 파악하는 것! 즉 추상화란 구체적인 것을 분해해서 관찰자가 관심있는 특성만 가지고 재조합하는 것이며 이는 곧 모델링이라고 할 수 있다.


객체 - 세상에 존재하는 유일무이한 사물

클래스 - 분류, 집합, 같은 속성과 기능을 가진 객체를 총칭하는 개념


세상에 존재하는 유일무이한 객체를 특성(속성 + 기능) 에 따라 분류해 보니 객체를 통칭할 수 있는 집합적 개념, 즉 클래스가 나오게 된다. 따라서 클래스는 같은 특성을 지닌 여러 객체를 총칭하는 집합의 개념이다.


애플리케이션 경계 - Context

내가 만들고자 하는 애플리케이션은 어디에서 사용될 것인가?에 대한 답이 바로 Context다.

즉 Context에 따라 클래스의 설계가 달라질 수 있다는 것이다. 


여기까지 다시 개념정리를 했다면 추상화를 다시 정의해 보도록 하겠다.

추상화란 구체적인 것을 분해해서 관심 영영(Context) 있는 특성만 가지고 재조합하는 것이다. == 모델링


이러한 모델링은 실제 사물을 정확히 복제하는 것이 아니라 목적에 맞게 관심있는 특성만을 추출해서 표현하는 것이다. 클래스를 설계하거나 데이터베이스 테이블을 설계할 때 필요한 기법이기도 하다.


자바에서는 이러한 추상화를 class 키워드를 통해 지원하고 있다. 

추상화 = 모델링 = class키워드


반응형

+ Recent posts