문제

 

보글(Boggle) 게임은 그림 (a)와 같은 5x5 크기의 알파벳 격자인 게임판의 한 글자에서 시작해서 펜을 움직이면서 만나는 글자를 그 순서대로 나열하여 만들어지는 영어 단어를 찾아내는 게임입니다. 펜은 상하좌우, 혹은 대각선으로 인접한 칸으로 이동할 수 있으며 글자를 건너뛸 수는 없습니다. 지나간 글자를 다시 지나가는 것은 가능하지만, 펜을 이동하지않고 같은 글자를 여러번 쓸 수는 없습니다.

예를 들어 그림의 (b), (c), (d)는 각각 (a)의 격자에서 PRETTY, GIRL, REPEAT을 찾아낸 결과를 보여줍니다.

보글 게임판과 알고 있는 단어들의 목록이 주어질 때, 보글 게임판에서 각 단어를 찾을 수 있는지 여부를 출력하는 프로그램을 작성하세요.

입력

입력의 첫 줄에는 테스트 케이스의 수 C(C <= 50)가 주어집니다. 각 테스트 케이스의 첫 줄에는 각 5줄에 5글자로 보글 게임판이 주어집니다. 게임판의 모든 칸은 알파벳 대문자입니다.
그 다음 줄에는 우리가 알고 있는 단어의 수 N(1 <= N <= 10)이 주어집니다. 그 후 N줄에는 한 줄에 하나씩 우리가 알고 있는 단어들이 주어집니다. 각 단어는 알파벳 대문자 1글자 이상 10글자 이하로 구성됩니다.

출력

각 테스트 케이스마다 N줄을 출력합니다. 각 줄에는 알고 있는 단어를 입력에 주어진 순서대로 출력하고, 해당 단어를 찾을 수 있을 경우 YES, 아닐 경우 NO를 출력합니다.

예제 입력

1

URLPM

XPRET

GIAET

XTNZY

XOQRS

6

PRETTY

GIRL

REPEAT

KARA

PANDORA

GIAZAPX

예제 출력

PRETTY YES

GIRL YES

REPEAT YES

KARA NO

PANDORA NO

GIAZAPX YES

코드

 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char boggle[7][7];
char buf[100];
char word[10][11];
int prev[2][10];
int start[7][7];
int mark[7][7][10];
int loc[2];
int idx;
int len;
int move[8][2] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};
int main(){
	char temp;
	int row_ct, col_ct;
	int C, N;
	int i, j, k, t, p, q, offset, x, y, result;
	
	scanf("%d%c", &C, &temp);
	for(i = 0; i < C; i++){	
		for(j = 0; j < 7; j++){
			for(k = 0; k < 7; k++){
				boggle[j][k] = 0;
			}
		}
		for(j = 1; j < 6; j++){
			scanf("%s", &boggle[j][1]);
		}
		scanf("%d%c", &N, &temp);
		for(j = 0; j < N; j++){
			scanf("%s", word[j]);
		}
		for(j = 0; j < N; j++){
			result = 0;
			len = strlen(word[j]);
			for(x = 1; x < 6; x++){
				for(y = 1 ; y < 6; y++){
					if(boggle[x][y] == word[j][0]){
						memset(mark, 0, sizeof(mark));
						idx = 0;
						loc[0] = x;
						loc[1] = y;
						prev[0][idx] = x;
						prev[1][idx] = y;
						idx++;
						while(idx < len){
							for(k = 0; k < 8; k++){
								if(mark[loc[0] + move[k][0]][loc[1] + move[k][1]][idx] == 0 && boggle[loc[0] + move[k][0]][loc[1] + move[k][1]] == word[j][idx]){
									loc[0] = loc[0] + move[k][0];
									loc[1] = loc[1] + move[k][1];
									prev[0][idx] = loc[0];
									prev[1][idx] = loc[1];
									idx++;
									break;
								}
							}
							if(k == 8){
								idx--;
								mark[loc[0]][loc[1]][idx] = 1;
								if(idx == 0)
									break;
								loc[0] = prev[0][idx-1];
								loc[1] = prev[1][idx-1];
							}
						}
						if(idx == len){
							result = 1;
							break;
						}
					}
				}
				if(result == 1)
					break;
			}
			if(result == 1){
				printf("%s YES\n", word[j]);
			}
			else{
				printf("%s NO\n", word[j]);
			}
		}
	}
}

해설

다이나믹 프로그래밍에 관한 문제이다. 재귀 함수로 짤 수도 있지만 귀찮아서 반복문으로 해결 했다. 문제 해결 스텝은 다음과 같다.

 

do 글자 탐색

>>if 글자가 있을 경우,

        위치 정보를 저장하고 인덱스 증가

   else 글자가 없을 경우,

        막다른 길로 표시하고 인덱스 감소 후 다시 위치 지정

 

중요한 점은 글자 탐색 조건에 표시(mark 배열)한 곳에 대한 조건도 같이 넣어줘야 한다는 점이다.

낙서

문제를 잘못 읽어서 삽질을 너무 많이 한 문제이다. '보글(Boggle) 게임은 그림 (a)와 같은 5x5 크기의 알파벳 격자인 게임판의 한 글자에서 시작해서 펜을 움직이면서 만나는 글자를 그 순서대로 나열하여 만들어지는 영어 단어를 찾아내는 게임입니다.' 이 문장에서 순서대로란 말에 주목했어야 하는데, 순서대로란 말은 즉 현재 위치에서 펜을 한칸만 움직여서 다음 글자에 도달할 수 있어야 한다는 것이다. 처음에는 이 말을 빼먹고 문제를 읽어서 그냥 현재까지 찾은 글자들에 인접한 곳에 다음 글자가 있으면 되는 문제로 생각해서 굉장히 복잡하게 풀고 있다가, 문제를 다시 읽고 허무해졌다. 문제를 잘 읽자!

'algo' 카테고리의 다른 글

algospot - FESTIVAL  (0) 2019.08.08

문제

커다란 공연장을 빌려서 록 페스티벌을 개최하려고 합니다. 이 페스티벌은 여러 날 동안 진행되며, 하루에 한 팀의 밴드가 공연장에서 콘서트를 하게 됩니다. 전체 밴드를 몇 팀 섭외할 지는 아직 결정하지 않았지만, 페스티벌의 간판 스타인 L개의 팀은 이미 섭외가 끝난 상태입니다. 따라서 페스티벌은 최소 L일 이상 진행하게 됩니다.

이번에 사용할 공연장은 하루 빌리는 데 드는 비용이 매일 매일 다릅니다. 때문에 공연 일정을 잘 정해서 공연장 대여 비용을 줄이려고 합니다. 앞으로 N일간의 공연장 대여 비용을 알고 있다고 합시다. 이 중 L일 이상을 연속해서 대여하되, 공연장을 하루 빌리는 데 드는 평균 비용을 최소화하려면 어떻게 공연장을 빌려야 할까요?

예를 들어 앞으로 6일간 공연장을 빌리는 데 드는 비용이 각 {3, 1, 2, 3, 1, 2}라고 합시다. 이미 세 팀을 섭외했다고 하면, 3일 대신 4일 동안 공연을 진행해서 평균 비용을 더 저렴하게 할 수 있습니다. 3일 동안의 평균 대여 비용을 최소화하는 방법은 2일째부터 4일째까지 공연장을 대여하는 것인데, 이 때 하루 평균 (1+2+3)/3 = 2의 비용이 듭니다. 반면 2일째부터 5일째까지 공연장을 대여하면 평균 비용이 (1+2+3+1)/4 = 7/4밖에 되지 않습니다.

입력

입력의 첫 줄에는 테스트 케이스의 수 C (C ≤ 100)가 주어집니다. 각 테스트 케이스의 첫 줄에는 공연장을 대여할 수 있는 날들의 수 N (1 ≤ N ≤ 1000)과 이미 섭외한 공연 팀의 수 L (1 ≤ L ≤ 1000, L ≤ N)이 주어집니다. 그 다음 줄에는 N개의 숫자로 공연장 대여 비용이 날짜별로 주어집니다. 모든 비용은 100 이하의 자연수입니다.

출력

입력에 주어지는 각 테스트 케이스마다 한 줄에 최소의 평균 대여 비용을 출력합니다. 10-7 이하의 절대/상대 오차가 있는 답은 정답 처리됩니다.

 

예제 입력

2

6 3

1 2 3 1 2 3

6 2

1 2 3 1 2 3

 

예제 출력

1.75000000000

1.50000000000

코드

#include <stdio.h>

int cost[1000];

int main(){
	char temp;
	int C, N, L;
	int i, j, k;
	int size, offset, iter, sum;
	double avg, min;

	scanf("%d", &C);

	for(i = 0; i < C; i++){
		min = 100000;
		scanf("%d %d", &N, &L);
		j = 0;

		do {
			scanf("%d%c", &cost[j], &temp);
			j++;
		} while(temp != '\n');

		for(k = L; k <= N; k++){
			size = k;
			offset = 0;

			do {
				iter = 0;
				sum = 0;

				do {
					sum += cost[offset+iter];
					iter++;
				} while(iter < size);

				avg = (double)sum / size;

				if(avg < min)
					min = avg;
				
				offset++;
			} while(offset + size <= N);

		}

		printf("%.11lf\n", min);
	}

	return 0;
}

해설

공연장을 연속으로 빌리는 최소 일 수 L부터 N까지의 공연 평균 비용을 전부 계산 했다. 예를 들어 N = 6, L = 3이고, 비용은 (1, 2, 3, 1, 2, 3)일 때, 공연을 빌리는 일 수를 size라고 하면, 다음과 같은 경우의 수가 발생한다.

 

i) size = 3(L부터)

(1, 2, 3), (2, 3, 1), (3, 1, 2), (1, 2, 3)

ii) size = 4

(1, 2, 3, 1), (2, 3, 1, 2), (3, 1, 2, 3)

iii) size = 5

(1, 2, 3, 1, 2), (2, 3, 1, 2, 3)

iv) size = 6(N까지)

(1, 2, 3, 1, 2, 3)

 

각 경우의 수의 평균 비용을 모두 계산하고, 최소 평균 비용을 구한다.

낙서

출력할 때 소수점 자릿수를 맞춰주지 않으면 답으로 인정되지 않는 것 같다.

 

출처: https://algospot.com/judge/problem/read/FESTIVAL

'algo' 카테고리의 다른 글

algospot - BOGGLE  (0) 2019.08.26

+ Recent posts