N×M크기의 배열로 표현되는 미로가 있다.

1 0 1 1 1 1
1 0 1 0 1 0
1 0 1 0 1 1
1 1 1 0 1 1

미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다.

위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.

입력

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

출력

첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.

예제 입력 1

4 6
101111
101010
101011
111011

예제 출력 1

15

예제 입력 2

4 6
110110
110110
111111
111101

예제 출력 2

9

예제 입력 3

2 25
1011101110111011101110111
1110111011101110111011101

예제 출력 3

38

예제 입력 4

7 7
1011111
1110001
1000001
1000001
1000001
1000001
1111111

예제 출력 4

13

더보기

Solution

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

int main(void)
{
	int N, M, **miro=NULL, *queue=NULL, front=0, rear=0, count=1;
	bool **visited=NULL;
	scanf("%d%d", &N, &M);
	miro=(int **)malloc(N*sizeof(int  *));
	visited=(bool **)malloc(N*sizeof(bool *));
	queue=(int *)malloc(N*M*sizeof(int));
	for(int n=0;n<N;n++)
	{
		miro[n]=(int *)malloc(M*sizeof(int));
		visited[n]=(bool *)calloc(M,sizeof(bool));

		for(int m=0;m<M;m++)
			scanf("%1d", &miro[n][m]);
	}

	visited[0][0]=true;
	queue[rear++]=0;

	while(front<rear && !visited[N-1][M-1])
	{
		int previous_rear=rear;

		while(front<previous_rear && !visited[N-1][M-1])
		{
			int y=queue[front]%1000, x=queue[front]/1000;

			if(x+1<N &&  miro[x+1][y]==1 &&!visited[x+1][y] )
			{
				visited[x+1][y]=true;
				queue[rear++]=1000*(x+1)+y;
			}
			if(y+1<M && miro[x][y+1]==1 && !visited[x][y+1])
			{
				visited[x][y+1]=true;
				queue[rear++]=1000*x+y+1;
			}
			if(x>0 &&  miro[x-1][y]==1 &&!visited[x-1][y] )
			{
				visited[x-1][y]=true;
				queue[rear++]=1000*(x-1)+y;
			}
			if(y>0 && miro[x][y-1]==1 && !visited[x][y-1])
			{
				visited[x][y-1]=true;
				queue[rear++]=1000*x+y-1;
			}

			front++;
		}
		count++;
	}

	printf("%d\n", count);
	free(queue);
	for(int n=0;n<N;n++)
	{
		free(visited[n]);
		free(miro[n]);
	}
	free(visited);
	free(miro);
	return 0;
}
728x90

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다.

1번 2번 3번 4번 5번

1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할 수 있다.

CCTV는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다. 사무실에는 벽이 있는데, CCTV는 벽을 통과할 수 없다. CCTV가 감시할 수 없는 영역은 사각지대라고 한다.

CCTV는 회전시킬 수 있는데, 회전은 항상 90도 방향으로 해야 하며, 감시하려고 하는 방향이 가로 또는 세로 방향이어야 한다.

0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0

지도에서 0은 빈 칸, 6은 벽, 1~5는 CCTV의 번호이다. 위의 예시에서 1번의 방향에 따라 감시할 수 있는 영역을 '#'로 나타내면 아래와 같다.

0 0 0 0 0 0 
0 0 0 0 0 0
0 0 1 # 6 0
 0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
# # 1 0 6 0
0 0 0 0 0 0
0 0 # 0 0 0
0 0 # 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 # 0 0 0
 →

CCTV는 벽을 통과할 수 없기 때문에, 1번이 → 방향을 감시하고 있을 때는 6의 오른쪽에 있는 칸을 감시할 수 없다.

0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5

위의 예시에서

감시할 수 있는 방향을 알아보면 아래와 같다.

0 0 0 0 0 #
# 2 # # # #
0 0 0 0 6 #
0 6 # # 2 #
0 0 0 0 0 #
# # # # # 5
0 0 0 0 0 #
# 2 # # # #
0 0 0 0 6 #
0 6 0 0 2 #
0 0 0 0 # #
# # # # # 5
0 # 0 0 0 #
0 2 0 0 0 #
0 # 0 0 6 #
0 6 # # 2 #
0 0 0 0 0 #
# # # # # 5
0 # 0 0 0 #
0 2 0 0 0 #
0 # 0 0 6 #
0 6 0 0 2 #
0 0 0 0 # #
# # # # # 5
왼쪽 상단 2: ↔, 오른쪽 하단 2: ↔ 왼쪽 상단 2: ↔, 오른쪽 하단 2: ↕ 왼쪽 상단 2: ↕, 오른쪽 하단 2: ↔ 왼쪽 상단 2: ↕, 오른쪽 하단 2: ↕

CCTV는 CCTV를 통과할 수 있다. 아래 예시를 보자.

0 0 2 0 3
0 6 0 0 0
0 0 6 6 0
0 0 0 0 0

위와 같은 경우에 2의 방향이 ↕ 3의 방향이 ←와 ↓인 경우 감시받는 영역은 다음과 같다.

# # 2 # 3
0 6 # 0 #
0 0 6 6 #
0 0 0 0 #

사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 사무실의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 8)

둘째 줄부터 N개의 줄에는 사무실 각 칸의 정보가 주어진다. 0은 빈 칸, 6은 벽, 1~5는 CCTV를 나타내고, 문제에서 설명한 CCTV의 종류이다. 

CCTV의 최대 개수는 8개를 넘지 않는다.

출력

첫째 줄에 사각 지대의 최소 크기를 출력한다.

예제 입력 1

4 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0

예제 출력 1

20

예제 입력 2

6 6
0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5

예제 출력 2

15

예제 입력 3

6 6
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1

예제 출력 3

6

예제 입력 4

6 6
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 5 0 0
0 0 5 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1

예제 출력 4

2

예제 입력 5

1 7
0 1 2 3 4 5 6

예제 출력 5

0

예제 입력 6

3 7
4 0 0 0 0 0 0
0 0 0 2 0 0 0
0 0 0 0 0 0 4

예제 출력 6

0

더보기

Solution

#include<stdio.h>
#include<stdlib.h>

int N, M, CCTV_count=0, *CCTV=NULL, **office=NULL;

int blind_spot(int current)
{
	if(current==CCTV_count)
	{
		int area=0, wall_count=0;

		for(int i=0;i<CCTV_count;i++)
		{
			int x=CCTV[i]/10, y=CCTV[i]%10;

			if((office[x][y]&(1<<3))!=0)
			{
				while(x>0 && office[x-1][y]!=6)
				{
					x--;
					if(office[x][y]==0)
						office[x][y]=-1;
				}
				x=CCTV[i]/10;
				y=CCTV[i]%10;
			}
			if((office[x][y]&(1<<4))!=0)
			{
				while(x<N-1 && office[x+1][y]!=6)
				{
					x++;
					if(office[x][y]==0)
						office[x][y]=-1;
				}
				x=CCTV[i]/10;
				y=CCTV[i]%10;
			}
			if((office[x][y]&(1<<5))!=0)
			{
				while(y>0 && office[x][y-1]!=6)
				{
					y--;
					if(office[x][y]==0)
						office[x][y]=-1;
				}
				x=CCTV[i]/10;
				y=CCTV[i]%10;
			}
			if((office[x][y]&(1<<6))!=0)
			{
				while(y<M-1 && office[x][y+1]!=6)
				{
					y++;
					if(office[x][y]==0)
						office[x][y]=-1;
				}
				x=CCTV[i]/10;
				y=CCTV[i]%10;
			}
		}

		for(int n=0;n<N;n++)
			for(int m=0;m<M;m++)
				if(office[n][m]==-1)
					office[n][m]=0;
				else if(office[n][m]==0)
					area++;

		return area;
	}

	int x=CCTV[current]/10, y=CCTV[current]%10, min=64, temp;

	switch(office[x][y])
	{
		case 1:
			office[x][y]|=1<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=1<<3;
			office[x][y]|=1<<4;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=1<<4;
			office[x][y]|=1<<5;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=1<<5;
			office[x][y]|=1<<6;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=1<<6;
			break;
		case 2:
			office[x][y]|=3<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=3<<3;
			office[x][y]|=3<<5;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=3<<5;
			break;
		case 3:
			office[x][y]|=5<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=5<<3;
			office[x][y]|=9<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=9<<3;
			office[x][y]|=3<<4;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=3<<4;
			office[x][y]|=5<<4;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=5<<4;
			break;
		case 4:
			office[x][y]|=14<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=14<<3;
			office[x][y]|=13<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=13<<3;
			office[x][y]|=11<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=11<<3;
			office[x][y]|=7<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=7<<3;
			break;
		case 5:
			office[x][y]|=15<<3;
			temp=blind_spot(current+1);
			if(temp<min)
				min=temp;
			office[x][y]^=15<<3;
			break;
		default:
			break;
	}

	return min;
}

int main(void)
{
	scanf("%d%d", &N, &M);
	office=(int **)malloc(N*sizeof(int *));
	for(int n=0;n<N;n++)
	{
		office[n]=(int *)malloc(M*sizeof(int));

		for(int m=0;m<M;m++)
		{
			scanf("%d", &office[n][m]);
			if(office[n][m]>0 && office[n][m]<6)
				CCTV_count++;
		}
	}

	CCTV=(int *)malloc(CCTV_count*sizeof(int));
	CCTV_count=0;

	for(int n=0;n<N;n++)
		for(int m=0;m<M;m++)
			if(office[n][m]>0 && office[n][m]<6)
				CCTV[CCTV_count++]=10*n+m;

	printf("%d\n", blind_spot(0));
	free(CCTV);
	for(int n=0;n<N;n++)
		free(office[n]);
	free(office);
	return 0;
}
728x90

숫자 1, 2, 3으로만 이루어지는 수열이 있다. 임의의 길이의 인접한 두 개의 부분 수열이 동일한 것이 있으면, 그 수열을 나쁜 수열이라고 부른다. 그렇지 않은 수열은 좋은 수열이다.

다음은 나쁜 수열의 예이다.

  • 33
  • 32121323
  • 123123213

다음은 좋은 수열의 예이다.

  • 2
  • 32
  • 32123
  • 1232123

길이가 N인 좋은 수열들을 N자리의 정수로 보아 그중 가장 작은 수를 나타내는 수열을 구하는 프로그램을 작성하라. 예를 들면, 1213121과 2123212는 모두 좋은 수열이지만 그 중에서 작은 수를 나타내는 수열은 1213121이다.

입력

입력은 숫자 N하나로 이루어진다. N은 1 이상 80 이하이다.

출력

첫 번째 줄에 1, 2, 3으로만 이루어져 있는 길이가 N인 좋은 수열들 중에서 가장 작은 수를 나타내는 수열만 출력한다. 수열을 이루는 1, 2, 3들 사이에는 빈칸을 두지 않는다.

예제 입력 1

7

예제 출력 1

1213121

더보기

Solution

#include<stdio.h>
#include<stdbool.h>

int N, number[80]={0, };
bool found=false;

bool find_good(int index)
{
	for(int i=1;i<=index/2;i++)
	{
		bool same=true;

		for(int j=0;j<i;j++)
			if(number[index-j-1]!=number[index-i-j-1])
			{
				same=false;
				break;
			}

		if(same)
			return false;
	}

	return true;
}

void good_number(int index)
{
	if(found)
		return;
	if(index==1)
	{
		number[0]++;
		good_number(2);
	}
	else if(index==N+1)
	{
		if(find_good(index))
		{
			found=true;
			for(int i=0;i<N;i++)
				printf("%d", number[i]);
			printf("\n");
			return;
		}
		else
			find_good(index-1);
	}
	else
	{
		while(number[index-1]<3)
		{
			number[index-1]++;
			if(find_good(index))
			{
				good_number(index+1);
				break;
			}
		}
		if(!found)
		{
			number[index-1]=0;
			good_number(index-1);
		}
	}
}

int main(void)
{
	scanf("%d", &N);
	good_number(1);
	return 0;
}
728x90

크기가 N인 수열 A = A[1], A[2], ..., A[N]이 있다. 수열의 각 원소 A[i]에 대해서 오등큰수 NGF(i)를 구하려고 한다.

Ai가 수열 A에서 등장한 횟수를 F(A[i])라고 했을 때, A[i]의 오등큰수는 오른쪽에 있으면서 수열 A에서 등장한 횟수가 F(A[i])보다 큰 수 중에서 가장 왼쪽에 있는 수를 의미한다. 그러한 수가 없는 경우에 오등큰수는 -1이다.

예를 들어, A = [1, 1, 2, 3, 4, 2, 1]인 경우 F(1) = 3, F(2) = 2, F(3) = 1, F(4) = 1이다. A[1]의 오른쪽에 있으면서 등장한 횟수가 3보다 큰 수는 없기 때문에, NGF(1) = -1이다. A[3]의 경우에는 A[7]이 오른쪽에 있으면서 F(A[3]=2) < F(A[7]=1) 이기 때문에, NGF(3) = 1이다. NGF(4) = 2, NGF(5) = 2, NGF(6) = 1 이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째에 수열 A의 원소 A[1], A[2], ..., A[N] (1 ≤ A[i] ≤ 1,000,000)이 주어진다.

출력

총 N개의 수 NGF(1), NGF(2), ..., NGF(N)을 공백으로 구분해 출력한다.

예제 입력 1

7
1 1 2 3 4 2 1

예제 출력 1

-1 -1 1 2 2 1 -1

더보기

Solution

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
	int N, *A=NULL, *NGF=NULL, *stack=NULL, current=0, *frequency=NULL, max=0;

	scanf("%d", &N);
	A=(int *)malloc(N*sizeof(int));
	NGF=(int *)calloc(N,sizeof(int));
	stack=(int *)malloc(N*sizeof(int));

	for(int n=0;n<N;n++)
	{
		scanf("%d", &A[n]);
		if(A[n]>max)
			max=A[n];
	}

	frequency=(int *)calloc(max+1,sizeof(int));
	for(int n=0;n<N;n++)
		frequency[A[n]]++;

	for(int n=0;n<N;n++)
	{
		while(current>0)
			if(frequency[A[stack[current-1]]]<frequency[A[n]])
				NGF[stack[--current]]=A[n];
			else
				break;

		stack[current++]=n;
	}

	for(int n=0;n<N;n++)
		printf("%d ", NGF[n]==0?-1:NGF[n]);
	printf("\n");
	free(frequency);
	free(NGF);
	free(stack);
	free(A);
	return 0;
}
728x90

도시에는 N개의 빌딩이 있다.

빌딩 관리인들은 매우 성실 하기 때문에, 다른 빌딩의 옥상 정원을 벤치마킹 하고 싶어한다.

i번째 빌딩의 키가 h[i]이고, 모든 빌딩은 일렬로 서 있고 오른쪽으로만 볼 수 있다.

i번째 빌딩 관리인이 볼 수 있는 다른 빌딩의 옥상 정원은 i+1, i+2, .... , N이다.

그런데 자신이 위치한 빌딩보다 높거나 같은 빌딩이 있으면 그 다음에 있는 모든 빌딩의 옥상은 보지 못한다.

예) N=6, H = {10, 3, 7, 4, 12, 2}인 경우

             = 
 =           = 
 =     -     = 
 =     =     =        -> 관리인이 보는 방향
 =  -  =  =  =   
 =  =  =  =  =  = 
10  3  7  4  12 2     -> 빌딩의 높이
[1][2][3][4][5][6]    -> 빌딩의 번호
  • 1번 관리인은 2, 3, 4번 빌딩의 옥상을 확인할 수 있다.
  • 2번 관리인은 다른 빌딩의 옥상을 확인할 수 없다.
  • 3번 관리인은 4번 빌딩의 옥상을 확인할 수 있다.
  • 4번 관리인은 다른 빌딩의 옥상을 확인할 수 없다.
  • 5번 관리인은 6번 빌딩의 옥상을 확인할 수 있다.
  • 6번 관리인은 마지막이므로 다른 빌딩의 옥상을 확인할 수 없다.

따라서, 관리인들이 옥상정원을 확인할 수 있는 총 수는 3 + 0 + 1 + 0 + 1 + 0 = 5이다.

입력

  • 첫 번째 줄에 빌딩의 개수 N이 입력된다.(1 ≤ N ≤ 80,000)
  • 두 번째 줄 부터 N+1번째 줄까지 각 빌딩의 높이가 h[i] 입력된다. (1 ≤ h[i] ≤ 1,000,000,000)

출력

  • 각 관리인들이 벤치마킹이 가능한 빌딩의 수의 합을 출력한다.

예제 입력 1

6
10
3
7
4
12
2

예제 출력 1

5

더보기

Solution

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
	int N, *h=NULL, *bigger=NULL;
	long long sum=0;

	scanf("%d", &N);
	h=(int *)malloc(N*sizeof(int));
	bigger=(int *)malloc(N*sizeof(int));

	for(int n=0;n<N;n++)
		scanf("%d", &h[n]);

	bigger[N-1]=N;
	for(int n=N-2;n>=0;n--)
	{
		int next_bigger=n+1;

		while(next_bigger<N && h[next_bigger]<h[n])
			next_bigger=bigger[next_bigger];

		bigger[n]=next_bigger;
		sum+=bigger[n]-n-1;
	}

	printf("%lld\n", sum);
	free(bigger);
	free(h);
	return 0;
}
728x90

한수는 크기가 2^N × 2^N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다.

N > 1인 경우, 배열을 크기가 2^(N-1) × 2^(N-1)로 4등분 한 후에 재귀적으로 순서대로 방문한다.

다음 예는 2^2 × 2^2 크기의 배열을 방문한 순서이다.

N이 주어졌을 때, r행 c열을 몇 번째로 방문하는지 출력하는 프로그램을 작성하시오.

다음은 N=3일 때의 예이다.

입력

첫째 줄에 정수 N, r, c가 주어진다.

출력

r행 c열을 몇 번째로 방문했는지 출력한다.

제한

  • 1 ≤ N ≤ 15
  • 0 ≤ r, c < 2^N

예제 입력 1

2 3 1

예제 출력 1

11

예제 입력 2

3 7 7

예제 출력 2

63

예제 입력 3

1 0 0

예제 출력 3

0

예제 입력 4

4 7 7

예제 출력 4

63

예제 입력 5

10 511 511

예제 출력 5

262143

예제 입력 6

10 512 512

예제 출력 6

786432

더보기

Solution

#include<stdio.h>

int main(void)
{
	int N, r, c, x=0, y=0, order=0;

	scanf("%d%d%d", &N, &r, &c);

	N--;
	while(x!=r || y!=c)
	{
		int shift=1<<N;
		if(x+shift<=r && y+shift<=c)
		{
			order+=3*shift*shift;
			x+=shift;
			y+=shift;
		}
		else if(x+shift<=r)
		{
			order+=2*shift*shift;
			x+=shift;
		}
		else if(y+shift<=c)
		{
			order+=shift*shift;
			y+=shift;
		}
		N--;
	}

	printf("%d\n", order);
	return 0;
}
더보기

Solution

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {	
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st=new StringTokenizer(br.readLine());

		int N=Integer.parseInt(st.nextToken());
		int r=Integer.parseInt(st.nextToken());
		int c=Integer.parseInt(st.nextToken());
		int x=0, y=0, order=0;
		
		N--;
		while(x!=r || y!=c) {
			int shift=1<<N;
			
			if(x+shift<=r && y+shift<=c) {
				order+=3*shift*shift;
				x+=shift;
				y+=shift;
			}
			else if(x+shift<=r) {
				order+=2*shift*shift;
				x+=shift;
			}
			else if(y+shift<=c) {
				order+=shift*shift;
				y+=shift;
			}

			N--;
		}
		
		System.out.println(order);
	}
}

 

728x90

흑백 영상을 압축하여 표현하는 데이터 구조로 쿼드 트리(Quad Tree)라는 방법이 있다. 흰 점을 나타내는 0과 검은 점을 나타내는 1로만 이루어진 영상(2차원 배열)에서 같은 숫자의 점들이 한 곳에 많이 몰려있으면, 쿼드 트리에서는 이를 압축하여 간단히 표현할 수 있다.

주어진 영상이 모두 0으로만 되어 있으면 압축 결과는 "0"이 되고, 모두 1로만 되어 있으면 압축 결과는 "1"이 된다. 만약 0과 1이 섞여 있으면 전체를 한 번에 나타내지를 못하고, 왼쪽 위, 오른쪽 위, 왼쪽 아래, 오른쪽 아래, 이렇게 4개의 영상으로 나누어 압축하게 되며, 이 4개의 영역을 압축한 결과를 차례대로 괄호 안에 묶어서 표현한다

위 그림에서 왼쪽의 영상은 오른쪽의 배열과 같이 숫자로 주어지며, 이 영상을 쿼드 트리 구조를 이용하여 압축하면 "(0(0011)(0(0111)01)1)"로 표현된다. N ×N 크기의 영상이 주어질 때, 이 영상을 압축한 결과를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에는 영상의 크기를 나타내는 숫자 N 이 주어진다. N 은 언제나 2의 제곱수로 주어지며, 1 ≤ N ≤ 64의 범위를 가진다. 두 번째 줄부터는 길이 N의 문자열이 N개 들어온다. 각 문자열은 0 또는 1의 숫자로 이루어져 있으며, 영상의 각 점들을 나타낸다.

출력

영상을 압축한 결과를 출력한다.

예제 입력 1

8
11110000
11110000
00011100
00011100
11110000
11110000
11110011
11110011

예제 출력 1

((110(0101))(0010)1(0001))

더보기

Solution

#include<stdio.h>
#include<stdlib.h>

int **quad_tree=NULL;

void print_area(int index,int size)
{
	int x=index/100, y=index%100, count=0;

	for(int i=0;i<size;i++)
		for(int j=0;j<size;j++)
			count+=quad_tree[x+i][y+j];

	if(count==0)
		printf("0");
	else if(count==size*size)
		printf("1");
	else
	{
		printf("(");
		print_area(100*x+y,size/2);
		print_area(100*x+y+size/2,size/2);
		print_area(100*(x+size/2)+y,size/2);
		print_area(100*(x+size/2)+y+size/2,size/2);
		printf(")");
	}
}

int main(void)
{
	int N;

	scanf("%d", &N);
	quad_tree=(int **)malloc(N*sizeof(int *));
	for(int i=0;i<N;i++)
	{
		quad_tree[i]=(int *)malloc(N*sizeof(int));

		for(int j=0;j<N;j++)
			scanf("%1d", &quad_tree[i][j]);
	}

	print_area(0,N);
	printf("\n");

	for(int i=0;i<N;i++)
		free(quad_tree[i]);
	free(quad_tree);
	return 0;
}
더보기

Solution

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
	static int[][] quadTree;
	static StringBuilder sb = new StringBuilder();
	
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String str;
		
		int N=Integer.parseInt(br.readLine());
		quadTree=new int[N][N];
		
		for(int i=0;i<N;i++) {
			str=br.readLine();
			for(int j=0;j<N;j++)
				quadTree[i][j]=str.charAt(j)-'0';
		}
		
		printArea(0,N);

		System.out.println(sb.toString());
	}
	
	static void printArea(int index,int size) {
		int x=index/100, y=index%100, count=0;
		
		for(int i=0;i<size;i++)
			for(int j=0;j<size;j++)
				count+=quadTree[x+i][y+j];

		if(count==0)
			sb.append(0);
		else if(count==size*size)
			sb.append(1);
		else
		{
			sb.append("(");
			printArea(100*x+y,size/2);
			printArea(100*x+y+size/2,size/2);
			printArea(100*(x+size/2)+y,size/2);
			printArea(100*(x+size/2)+y+size/2,size/2);
			sb.append(")");
		}
	}
}

 

728x90

아래 <그림 1>과 같이 여러개의 정사각형칸들로 이루어진 정사각형 모양의 종이가 주어져 있고, 각 정사각형들은 하얀색으로 칠해져 있거나 파란색으로 칠해져 있다. 주어진 종이를 일정한 규칙에 따라 잘라서 다양한 크기를 가진 정사각형 모양의 하얀색 또는 파란색 색종이를 만들려고 한다.

전체 종이의 크기가 N×N(N=2^k, k는 1 이상 7 이하의 자연수) 이라면 종이를 자르는 규칙은 다음과 같다.

전체 종이가 모두 같은 색으로 칠해져 있지 않으면 가로와 세로로 중간 부분을 잘라서 <그림 2>의 I, II, III, IV와 같이 똑같은 크기의 네 개의 N/2 × N/2색종이로 나눈다. 나누어진 종이 I, II, III, IV 각각에 대해서도 앞에서와 마찬가지로 모두 같은 색으로 칠해져 있지 않으면 같은 방법으로 똑같은 크기의 네 개의 색종이로 나눈다. 이와 같은 과정을 잘라진 종이가 모두 하얀색 또는 모두 파란색으로 칠해져 있거나, 하나의 정사각형 칸이 되어 더 이상 자를 수 없을 때까지 반복한다.

위와 같은 규칙에 따라 잘랐을 때 <그림 3>은 <그림 1>의 종이를 처음 나눈 후의 상태를, <그림 4>는 두 번째 나눈 후의 상태를, <그림 5>는 최종적으로 만들어진 다양한 크기의 9장의 하얀색 색종이와 7장의 파란색 색종이를 보여주고 있다.

입력으로 주어진 종이의 한 변의 길이 N과 각 정사각형칸의 색(하얀색 또는 파란색)이 주어질 때 잘라진 하얀색 색종이와 파란색 색종이의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 전체 종이의 한 변의 길이 N이 주어져 있다. N은 2, 4, 8, 16, 32, 64, 128 중 하나이다. 색종이의 각 가로줄의 정사각형칸들의 색이 윗줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진다. 하얀색으로 칠해진 칸은 0, 파란색으로 칠해진 칸은 1로 주어지며, 각 숫자 사이에는 빈칸이 하나씩 있다.

출력

첫째 줄에는 잘라진 햐얀색 색종이의 개수를 출력하고, 둘째 줄에는 파란색 색종이의 개수를 출력한다.

예제 입력 1

8
1 1 0 0 0 0 1 1
1 1 0 0 0 0 1 1
0 0 0 0 1 1 0 0
0 0 0 0 1 1 0 0
1 0 0 0 1 1 1 1
0 1 0 0 1 1 1 1
0 0 1 1 1 1 1 1
0 0 1 1 1 1 1 1

예제 출력 1

9
7

더보기

Solution

#include<stdio.h>
#include<stdlib.h>

int **paper=NULL, white=0, blue=0;

void count_color(int locate,int N)
{
	int x=locate/1000, y=locate%1000, count=0;

	for(int i=0;i<N;i++)
		for(int j=0;j<N;j++)
			count+=paper[x+i][y+j];

	if(count==0)
		white++;
	else if(count==N*N)
		blue++;
	else
	{
		count_color(1000*x+y,N/2);
		count_color(1000*(x+N/2)+y,N/2);
		count_color(1000*x+y+N/2,N/2);
		count_color(1000*(x+N/2)+y+N/2,N/2);
	}
}

int main(void)
{
	int N;

	scanf("%d", &N);
	paper=(int **)malloc(N*sizeof(int *));
	for(int i=0;i<N;i++)
	{
		paper[i]=(int *)malloc(N*sizeof(int));

		for(int j=0;j<N;j++)
			scanf("%d", &paper[i][j]);
	}

	count_color(0,N);

	printf("%d\n%d\n", white, blue);
	for(int i=0;i<N;i++)
		free(paper[i]);
	free(paper);
	return 0;
}
728x90

+ Recent posts