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

블로그 메뉴

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

공지사항

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

인기 글

태그

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

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Plite

전자오락 공방

[C++]백준 - 4600번 문제
공부 및 정리/백준 코드

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

2021. 12. 6. 17:35

4600번: 정글의 법칙 (acmicpc.net)

 

4600번: 정글의 법칙

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 음수 -B와 양수 P가 주어진다. B는 다리의 수이고, P는 사람의 수이다. B와 P는 20을 넘지 않는다. (B가 음수로 주

www.acmicpc.net

 

4600번 : 정글의 법칙


상근이는 정글의 법칙의 상근족 족장이다. 이번에 떠날 곳은 아마존이고, 아마존의 희원 부족을 만났다. 희원 부족은 높은 나무 위에서 사는 부족이다. 이 나무는 줄로 만든 다리로 연결되어 있다.

마을이 생긴 이래로 처음으로 외부인이 왔기 때문에, 희원 부족의 부족장은 오랜 고민끝에 용기를 내어 나무에 자신들이 만든 다리를 건널 수 있는 기회를 주기로 했다.

각각의 다리는 동시에 지나갈 수 있는 사람의 수가 제한되어 있다. 만약, 이보다 많은 사람이 지나간다면, 희원 부족은 매우 놀랄 것이다.

"절대 이분들을 놀라게 하면 안 돼"

상근이는 희원 부족을 놀라게 하지 않으려고 한다. 이번 촬영은 다리를 최대한 빨리 건너는 것이다. 상근족의 족장 상근이는 희원 부족을 놀라게 하지 않기 위해서, 다음과 같은 두 가지 지시를 내렸다.

 

1. 한 번에 한 그룹!

어떤 다리를 두 명 또는 그 이상이 건널 수 있을 때는, 그 사람들은 한 그룹으로 정하고 동시에 다리를 건너게 한다. 이때, 다리가 무너지지 않게 하기 위해서 최대한 서로 붙어서 움직이고, 걸음걸이도 똑같이 맞추고 걷는다. 다리가 무너지지 않는다고 하더라도, 두 그룹이 동시에 같은 다리를 건널 수는 없다. 그 이유는 여러 그룹이 다리를 건너면 다리가 흔들리게 되고, 희원 부족은 매우 놀랄 것이다. 그룹의 구성원은 한 명이 될 수도 있다.

 

2. 계속 움직여!

만약, 건너는 사람이 없는 다리가 있다면, 최대한 많은 사람들이 그룹을 이루고 그 다리를 건너기 시작할 것이다. 물론, 이 방법은 다리를 가장 빠르게 건너는 방법은 아니다. 하지만, 희원 부족은 사람들이 다리를 건너지 않고 기다리고 있다면, 다리에 무슨 문제가 생긴 것으로 착각하고 매우 놀랄 수 있다.

다리의 정보와 사람의 수가 주어졌을 때, 위의 2가지 조건을 지키면서 모든 사람이 다리를 건너는데 드는 가장 빠른 시간을 구하는 프로그램을 작성하시오.

예를 들어, 9명이 2개의 다리를 건너는 경우를 생각해보자. 첫 번째 다리는 동시에 3명이 10초만에 건너갈 수 있고, 두 번째 다리는 4명이 60초만에 건너갈 수 있다.

첫 번째 상태는 (9 0 0)으로 나타낼 수 있다. 이 상태의 뜻은 9명이 첫 번째 다리를 건너기 위해 기다리고 있고, 두 번째 다리를 건너기 위해 기다리는 사람과 모든 다리를 건너는 사람은 없다는 뜻이다.

10초 후의 상태는 (6 3 0)이 될 것이고, 20초 후의 상태는 (3 3 /3:50/ 0)이 된다. 여기서 /3:50/의 뜻은 3명으로 이루어진 그룹이 두 번째 다리를 건너는 중이고, 50초 남았다는 뜻이다.

30초 후의 상태는 (0 6 /3:40/ 0)이 될 것이고, 70초 후의 상태는 (0 6 3)이 된다. 130초 후의 상태는 (0 2 7)이 되고 190초 후의 상태는 (0 0 9)가 된다. 다리를 건너는데 드는 가장 빠른 시간은 190초이다.

 

입력


입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 음수 -B와 양수 P가 주어진다. B는 다리의 수이고, P는 사람의 수이다. B와 P는 20을 넘지 않는다. (B가 음수로 주어지는 이유는 데이터를 구분하기 쉽게 하기 위해서이다) 다음 B개 줄에는 한 줄에 하나씩 다리의 정보가 주어진다. 입력으로 주어지는 다리를 순서대로 건너야 한다. 각 다리의 정보는 두 양의 정수 C와 T로 이루어져 있다. C는 동시에 건널 수 있는 사람의 수, T는 그 다리를 건너는데 드는 시간이다. C는 최대 5이고, T는 최대 100이다. 최대 C명으로 이루어진 한 그룹이 다리를 건너는 시간은 T이다. 이때, 그룹 구성원의 수와 걸리는 시간은 상관이 없다. 입력의 마지막 줄에는 0 0이 주어진다.

출력


각 테스트 케이스에 대해서, 모든 사람이 상근이의 명령을 지키면서 다리를 건너는데 드는 가장 빠른 시간을 출력한다.

 


 

생각해 볼 점


구현 문제입니다.

 

다리는 직렬로 이루어져있고, 시간 순으로 계속 상황을 체크해야할 필요가 있습니다.

 

 

 

중간 생략

 

이하 생략

 

 

대충 위의 순서대로 진행되겠습니다.

 

우리는 실제로 저것을 구현해야합니다.

 

실제로 땅 위에 있는 사람 수를 담는 배열,

실제로 다리를 건너는 중인 사람 수를 담는 배열,

다리 정보를 담는 배열

 

 

이렇게 배열들을 이용하고, 단위 시간에 따라 각 배열들의 상태를 체크,

 

실제로 모든 사람이 다리를 다 건넜을 때의 시간을 출력합니다.

 

이 때, 단위 시간을 그냥 1초로 하여 매 초마다 다리를 다 체크하면서 진행시키는 건

 

꽤나 효율이 떨어지기 때문에 (실제로 제출 시 통과하는 지는 안해 봐서 모릅니다)

 

 

이런 다리 정보에서 다리를 건너는 데 드는 시간들의 최대 공약수를 단위 시간으로 삼겠습니다.

 

위의 다리 정보 {10초, 60초}의 경우에는 10초 마다 한번씩 진행시켜주면 될 것 같습니다.

 

따라서, 이 문제를 푸는 순서는

 

1. 다리 정보, 사람 정보 받기

2. 다리를 건너는 데 드는 시간들의 최대 공약수 구하기

3. 최대공약수를 단위 시간 삼아 반복문을 돌려 문제 조건에 따라 상황 진행시키기

4. 상황 완료 후 최종 시간 출력

 

입니다.

 

기타 자세한 구현 방법은 코드와 주석을 참조하세요.

 

 

코드


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

//최대공약수 구하는 함수
int get_gcd(int A, int B)
{
	//Swap
	if (B < A)
	{
		A += B;
		B = A - B;
		A = A - B;
	}

	while (A)
	{
		int temp = B;
		B = A;
		A = temp % A;
	}
	return B;
}

//단위시간 구하기
int get_unit_time(pair<int, int> *bridges, int B)
{
	if (B == 1) return bridges[0].second;
	int gcd = bridges[0].second;
	for (int i = 1; i < B; i++)
	{
		gcd = get_gcd(gcd, bridges[i].second);
	}
	return gcd;
}

int main()
{
	int B, P;

	scanf("%d %d", &B, &P);
	B *= -1;
	while (B || P)
	{
		pair<int,int>* bridges = new pair<int, int>[B];       //다리 정보 <가용량, 건너는데 걸리는 시간>
		int* people = new int[B + 1];                        //땅에 있는 사람 수
		pair<int, int>* crossing = new pair<int, int>[B];    //다리를 건너는 중 <사람수, 건너기 시작한 시간>
		fill_n(people, B + 1, 0);
		people[0] = P;
		for (int i = 0; i < B; i++)
		{
			scanf("%d %d", &bridges[i].first, &bridges[i].second);
			crossing[i] = { 0, 0};
		}


		int t_unit = get_unit_time(bridges, B);    //단위 시간
		int timed = -t_unit;                       //시간 측정

		while (people[B] < P)
		{
			timed += t_unit;
			for (int i = 0; i < B; i++)
			{
				//다리를 다 건넜을 경우
				if (timed - crossing[i].second - bridges[i].second == 0)
				{
					people[i + 1] += crossing[i].first;
					crossing[i].first = 0;
				}
                //다리를 건너는 사람이 없는 경우 다리를 건너도록 함
				if (!crossing[i].first)
				{
					int num_cross = min(people[i], bridges[i].first);
					people[i] -= num_cross;
					crossing[i].first += num_cross;
					crossing[i].second = timed;
				}
			}
		}
		
		printf("%d\n", timed);
		delete[] bridges;
		delete[] people;
		delete[] crossing;
		scanf("%d %d", &B, &P);
		B *= -1;
	}
	return 0;
}

 

그 외


 

저작자표시 (새창열림)

'공부 및 정리 > 백준 코드' 카테고리의 다른 글

[C++]백준 - 7869번 문제  (0) 2021.12.07
[C++]백준 - 23082번 문제  (0) 2021.12.06
[C++]백준 - 2467번 문제  (0) 2021.12.04
[C++]백준 - 5670번 문제  (0) 2021.12.03
[C++]백준 - 16637번 문제  (0) 2021.12.03
    '공부 및 정리/백준 코드' 카테고리의 다른 글
    • [C++]백준 - 7869번 문제
    • [C++]백준 - 23082번 문제
    • [C++]백준 - 2467번 문제
    • [C++]백준 - 5670번 문제
    Plite
    Plite
    개발 일지, 게임 이야기 등을 적어두는 공간입니다.

    티스토리툴바