[경시대회] 소믈리에 구름이

2024. 5. 8. 14:37·알고리즘


문제 정리

  • 구름이가 가진 모든 와인 용량은 N-1로 통일
    • 7잔 이라면 와인의 용량은 6임
  • 한 병의 와인을 따를 시 N-1개 잔을 각 잔에 정확히 1만큼씩 따라야함
    • 7잔 이라면 7잔 중 6잔에 1만큼 씩 따라야함

문제 접근 방법 1

  • qsort 후 첫 번째 인덱스 제외한 나머지 인덱스 증가
    • 내림차순으로 정렬
  • 모든 인덱스가 같은지 검사하는 check 함수 작성해서 모든 인덱스가 같다면 종료

1차 시도

#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)

int compare(const void*a, const void*b) {
	return(*(int*)b - *(int*)a); //내림차순 
}

int check(int *arr,int n,int a){
	for(int i = 0 ; i < n ; i++){
		if(arr[i] != a)
			return -1;
	}
		return 1;
}

int main() {
	int n;

	scanf("%d", &n);
	int* arr = (int*)malloc(sizeof(int) * n);

	for (int i = 0; i < n; i++) { // 와인 용량 입력
		scanf("%d", &arr[i]);
	}

	// 용량 n-1로 맞추기
	// n-1 개 잔을 골라 각 잔에 1만큼씩 따른다.
	
	int count = 0;
	
	for(int k = 0 ; k < n*n ; k++){
		qsort(arr, n, sizeof(int), compare);
		for(int i = 1 ; i < n ; i++){
			arr[i]++;
		}
		count++;
		if(check(arr,n,arr[0])==1)
			break;
	}

	
	printf("%d", count);
	free(arr);

	return 0;
}

  • 문제에서 주어졌던 1, 2번의 테스트 케이스는 통과하였지만 나머지 테스트 케이스에서 TimeOut이 발생함
  • TimeOut이 발생한 이유
    • 가장 먼저 든 생각은 N의 범위 때문임
      • 1 ≤ N ≤ 200,000
      • N이 최악일 경우의 알고리즘을 구현하는 것이 중요해 보임
    • 시간복잡도 고려하지 않음
      • 위와 비슷한 이유이기도 하고 보다 나은 알고리즘이 있을 것이라 생각됨

 

2차 시도

#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)

int compare(const void*a, const void*b) {
	return(*(int*)b - *(int*)a); //내림차순 
}

int check(int *arr,int n,int a){
	for(int i = 0 ; i < n ; i++){
		if(arr[i] != a)
			return -1;
	}
	return 1;
}

int main() {
	int n;

	scanf("%d", &n);
	int* arr = (int*)malloc(sizeof(int) * n);

	for (int i = 0; i < n; i++) { // 와인 용량 입력
		scanf("%d", &arr[i]);
	}

	// 용량 n-1로 맞추기
	// n-1 개 잔을 골라 각 잔에 1만큼씩 따른다.
	
	int count = 0;
	
	for(int j = 0 ; j < n ; j++){
		for(int k = 0 ; k < n ; k++){
			qsort(arr, n, sizeof(int), compare);
			if(check(arr,n,arr[0])==1){
				break;
			}
			for(int i = 1 ; i < n ; i++){
				arr[i]++;
				if(i==n-1){
					count++;
				}
			}
		}
	}

	
	printf("%d", count);
	free(arr);

	return 0;
}
  • 초기 정렬 과정을 이중 for 문으로 개선하였음
  • 테스트 3번 케이스 통과

문제점

  • 결과적으로 삼중 for문임
  • 시간 복잡도는 O(n^3)

 

3차 시도

#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
int compare(const void* a, const void* b) {
    return (*(int*)b - *(int*)a); // 내림차순
}

int check(int* arr, int n, int a) {
    for (int i = 0; i < n; i++) {
        if (arr[i] != a)
            return -1;
    }
    return 1;
}

int main() {
    int n;

    scanf("%d", &n);
    int* arr = (int*)malloc(sizeof(int) * n);

    for (int i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
    }

    int count = 0;

    while (check(arr, n, arr[0]) != 1) {
        qsort(arr, n, sizeof(int), compare);
        for (int i = 1; i < n; i++) {
            arr[i]++;
        }
        count++;
    }

    printf("\n필요한 최소 와인 잔 : %d", count);
    free(arr);

    return 0;
}
  • 반복 탈출 조건을 check 함수를 이용함
  • 4번 케이스까지 성공

문제점

  • timeout 발생

문제 해결

  • 예제를 계속 보면서 떠오른 아이디어
    • 와인의 총 용량에서 입력된 와인 잔을 뺀다면 필요한 와인 잔이 나오지 않을까?
    • 7 [1 5 2 1 2 2 2] 에서 (총 용량)15 - (와인 잔)7 = (필요한 와인 잔)8
    • 7 [2 2 3 2 5 5 1] 에서 (총 용량)20 - (와인 잔)7 = (필요한 와인 잔)13
      • 예제와 같음
  • 범위 고려하여 long long int 사용

4차 시도

#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
typedef long long ll;
int main() {
    int n;
    scanf("%d", &n);

    ll* wine_capacity = (ll*)malloc(sizeof(ll) * n);

    for (int i = 0; i < n; i++) {
        scanf("%lld", &wine_capacity[i]);
    }

    ll total_wine = 0;

    for (int i = 0; i < n; i++) {
        total_wine += (ll)wine_capacity[i];
    }

    ll min_operations = total_wine - (ll)n;

    printf("%lld", min_operations);

    free(wine_capacity);

    return 0;
}

 

  • 90% 이상 성공하였음…
  • 억지 코드 같지만 위 알고리즘으로 문제 해결 가능할 듯 싶음

'알고리즘' 카테고리의 다른 글

[경시대회] 왜 아픈 상처에 소금을 뿌리십니까?  (0) 2024.05.08
[백준] 1300번 - K번째 수 (C언어) [Gold2]  (0) 2023.06.06
[백준] 11053번 - 가장 긴 증가하는 부분 수열 (C언어) [Silver2]  (0) 2023.06.02
[백준] 1517번 - 버블 소트 (C언어) [Platinum5]  (0) 2023.06.01
[백준] 2042번 - 구간 합 구하기 (C언어) [Gold1]  (0) 2023.05.31
'알고리즘' 카테고리의 다른 글
  • [경시대회] 왜 아픈 상처에 소금을 뿌리십니까?
  • [백준] 1300번 - K번째 수 (C언어) [Gold2]
  • [백준] 11053번 - 가장 긴 증가하는 부분 수열 (C언어) [Silver2]
  • [백준] 1517번 - 버블 소트 (C언어) [Platinum5]
min._.uuk_
min._.uuk_
하루 하나 기록하기
  • min._.uuk_
    기록하는 습관
    min._.uuk_
  • 전체
    오늘
    어제
    • 분류 전체보기 (34)
      • 알고리즘 (15)
      • 자바 스크립트 (2)
      • 인실리코젠 (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    #BOJ #백준 #10989번 #C언어 #카운팅정렬 #정렬
    백준 #BOJ #스택 #수열
    인실리코젠 #크롤링 #SpringBoot #MVC #jQuery
    백준 #후위표기식 #스택 #중위표기식 #우선순위 #1918번
    백준 #동적계획법 #dp #백트래킹 #dfs
    백준 #MST #최소비용신장트리 #크루스칼 #그리디 #알고리즘
    백준 #세그먼트 트리 #구간합 #c언어 #골드1 #탐색
    Apache #POI #JAVA #maven
    백준 #1407번 #재귀함수
    JS #테트리스 #HTML #CSS #추억의 게임
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
min._.uuk_
[경시대회] 소믈리에 구름이
상단으로

티스토리툴바