Plite
전자오락 공방
Plite
전체 방문자
오늘
어제
  • 분류 전체보기 (274)
    • 프로젝트 (18)
      • 완성 프로젝트 (3)
      • 프로젝트 진행 내역 (15)
    • 공부 및 정리 (241)
      • 백준 코드 (222)
      • C++ (8)
      • DirectX (2)
      • Unreal Engine (6)
      • 프로그래밍 패턴 (3)
    • 기타 (12)
      • 기타 주저리 (10)
    • 게임과 취미 (1)
    • 대문 (1)

블로그 메뉴

  • 홈
  • 프로젝트
  • 취미, 일상
  • 백준 프로필

공지사항

  • [Read Me]
  • 제 블로그에 방문하신 것을 환영합니다.

인기 글

태그

  • 수학
  • 큐
  • 최소 스패닝 트리
  • C++
  • 문자열
  • 조합론
  • 구현
  • 기하
  • 분할정복
  • 그래프
  • 누적합
  • KMP
  • 우선순위큐
  • 스택
  • 유니온 파인드
  • 위상 정렬
  • 동적계획법
  • 정렬
  • 이분탐색
  • 백트래킹
  • 정수론
  • LCA
  • UC++
  • 백준
  • 트리
  • 세그먼트 트리
  • 브루트포스
  • 트라이
  • 투포인터
  • SCC

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Plite

전자오락 공방

[C++]백준 - 2629번 문제
카테고리 없음

[C++]백준 - 2629번 문제

2021. 8. 8. 16:28

2629번: 양팔저울 (acmicpc.net)

 

2629번: 양팔저울

첫째 줄에는 추의 개수가 자연수로 주어진다. 추의 개수는 30 이하이다. 둘째 줄에는 추의 무게들이 자연수로 가벼운 것부터 차례로 주어진다. 같은 무게의 추가 여러 개 있을 수도 있다. 추의 무

www.acmicpc.net

 

2629번 : 양팔저울


양팔 저울과 몇 개의 추가 주어졌을 때, 이를 이용하여 입력으로 주어진 구슬의 무게를 확인할 수 있는지를 결정하려고 한다.

무게가 각각 1g과 4g인 두 개의 추가 있을 경우, 주어진 구슬과 1g 추 하나를 양팔 저울의 양쪽에 각각 올려놓아 수평을 이루면 구슬의 무게는 1g이다. 또 다른 구슬이 4g인지를 확인하려면 1g 추 대신 4g 추를 올려놓으면 된다.

구슬이 3g인 경우 아래 <그림 1>과 같이 구슬과 추를 올려놓으면 양팔 저울이 수평을 이루게 된다. 따라서 각각 1g과 4g인 추가 하나씩 있을 경우 주어진 구슬이 3g인지도 확인해 볼 수 있다.

<그림 1> 구슬이 3g인지 확인하는 방법 (1은 1g인 추, 4는 4g인 추, ●은 무게를 확인할 구슬)

 

<그림 2>와 같은 방법을 사용하면 구슬이 5g인지도 확인할 수 있다. 구슬이 2g이면 주어진 추를 가지고는 확인할 수 없다.

추들의 무게와 확인할 구슬들의 무게가 입력되었을 때, 주어진 추만을 사용하여 구슬의 무게를 확인 할 수 있는지를 결정하는 프로그램을 작성하시오.

<그림 2> 구슬이 5g인지 확인하는 방법

 

입력


첫째 줄에는 추의 개수가 자연수로 주어진다. 추의 개수는 30 이하이다. 둘째 줄에는 추의 무게들이 자연수로 가벼운 것부터 차례로 주어진다. 같은 무게의 추가 여러 개 있을 수도 있다. 추의 무게는 500g이하이며, 입력되는 무게들 사이에는 빈칸이 하나씩 있 다. 세 번째 줄에는 무게를 확인하고자 하는 구슬들의 개수가 주어진다. 확인할 구슬의 개수는 7이하이다. 네 번째 줄에는 확인하고자 하는 구슬들의 무게가 자연수로 주어지며, 입력되는 무게들 사이에는 빈 칸이 하나씩 있다. 확인하고자 하는 구슬의 무게는 40,000보다 작거나 같은 자연수이다.

 

 

출력


주어진 각 구슬의 무게에 대하여 확인이 가능하면 Y, 아니면 N 을 차례로 출력한다. 출력은 한 개의 줄로 이루어지며, 각 구슬에 대한 답 사이에는 빈칸을 하나씩 둔다.

 

 

 


 

생각해 볼 점


동적 프로그래밍 문제입니다.

 

냅색 알고리즘과 유사한 부분이 있습니다.

 

우선, Bool 타입의 이차원 배열 DP를 만들어서 다음과 같이 정의 합니다.

 

DP[index][weight]

 

index = index까지의 추를 사용할 때

weight = weight의 무게를 만들 수 있는가?

 

예를 들어 DP[3][5] = 1~3번째 추를 사용하여 5g을 만들 수 있는지의 여부

 

주의할 점은, 좌측에도 무게를 달 수 있으므로, 여러 추를 사용한 덧셈 및 뺄셈까지 고려해야합니다.

 

따라서, 다음과 같이 진행합니다.

 

예를들어, 추 5개 {2, 3, 3, 3, 3}을 받았을 때

 

DP[0] = 추를 한개도 사용하지 않으므로 모두 0입니다.

DP[1] = 1번째 추(2g)을 추가합니다. DP[1][2] = 1입니다.

DP[2] = 2번째 추(3g)을 추가합니다. DP[2][3] = 1입니다.

           DP[2]를 탐색하여 1인 항목이 있으면 다음을 진행합니다.

           1. DP[2]의 1인 항목의 무게 (2g) = 1 -> DP[3][2] = 1

           2. 해당 항목의 무게(2g) + 이번 추의 무게 -> DP[3][5] = 1

           3. (해당 항목의 무게(2g) - 이번 추의 무게)의 절댓값 -> DP[3][1] = 1

 

위의 과정을 반복하여

DP[모든 추의 갯수][확인하고 싶은 무게] == 1이면, Y 아니면 N을 출력합니다.

 

코드


#include <iostream>
#include <cmath>
using namespace std;

int main() 
{
    int w, m;
    cin >> w;
    
    int *weight = new int[w + 1];
    int max_weight = 0;
    for(int i = 1; i < w + 1; i++)
    {
        cin >> weight[i];
        max_weight += weight[i];
    }
    cin >> m;
    
    
    for(int i = 0; i < m; i++)
    {
        int marble;
        cin >> marble;
        
        bool **dp = new bool*[w + 1];   //i까지의 추로 해당 무게를 만들 수 있는가?
        dp[0] = new bool[max_weight + 1];
        fill_n(dp[0], max_weight + 1, false);
        
        //DP 알고리즘
        for(int j = 1; j < w + 1; j++)
        {
            dp[j] = new bool[max_weight + 1];
            fill_n(dp[j], max_weight, false);
            dp[j][weight[j]] = true;    //i번 째 추 = true
            
            //i-1번 째에 잴수 있었던 무게에서 i번째 추를 추가함
            for(int k = 0; k < max_weight + 1; k++)
            {
                if(dp[j-1][k])
                {
                    dp[j][k] = true;
                    int plus = k + weight[j];
                    int minus = abs(k - weight[j]);
                    
                    if(plus <= max_weight) dp[j][plus] = true;
                    if(minus <= max_weight) dp[j][minus] = true;
                }
            }
        }
        
        //출력
        if(dp[w][marble]) cout << "Y\n";
        else cout << "N\n";

        for(int j = 0; j < w + 1; j++) delete[] dp[j];
        delete[] dp;
    }
    delete[] weight;

	return 0;
}

 

그 외


 

저작자표시 (새창열림)
    Plite
    Plite
    개발 일지, 게임 이야기 등을 적어두는 공간입니다.

    티스토리툴바