스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 나중에 들어간 자료가 제일 먼저 나오는 (LIFO, Last in First out) 특성을 가지고 있다.

1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. 임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.

입력

첫 줄에 n (1 ≤ n ≤ 100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.

출력

입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.

예제 입력 1

8
4
3
6
8
7
5
2
1

예제 출력 1

+
+
+
+
-
-
+
+
-
+
+
-
-
-
-
-

예제 입력 2

5
1
2
5
3
4

예제 출력 2

NO

힌트

1부터 n까지에 수에 대해 차례로 [push, push, push, push, pop, pop, push, push, pop, push, push, pop, pop, pop, pop, pop] 연산을 수행하면 수열 [4, 3, 6, 8, 7, 5, 2, 1]을 얻을 수 있다.


더보기

Solution

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

int main(void)
{
	int n, current_num=0, current_char=0, number;
	bool *used=NULL, able=true;
	char string[1000000]={'\0', };

	scanf("%d", &n);
	used=(bool *)calloc(n+1,sizeof(bool));

	for(int i=0;i<n&&able;i++)
	{
		scanf("%d", &number);

		if(current_num==number)
		{
			string[current_char++]='-';
			used[number]=true;
		}
		else if(current_num<number)
		{
			while(current_num<number)
			{
				if(!used[current_num])
					string[current_char++]='+';
				current_num++;
			}
			string[current_char++]='-';
			used[number]=true;
		}
		else
		{
			while(used[current_num] && current_num>0)
				current_num--;

			if(current_num!=number)
			{
				able=false;
				break;
			}
			string[current_char++]='-';
			used[number]=true;
		}
		while(current_num>0&&used[current_num])
			current_num--;
	}

	if(able)
		for(int i=0;i<current_char;i++)
			printf("%c\n", string[i]);
	else
		printf("NO\n");
	free(used);
	return 0;
}
728x90

UCPC는 '전국 대학생 프로그래밍 대회 동아리 연합 여름 대회'의 줄임말로 알려져있다. 하지만 이 줄임말이 정확히 어떻게 구성되었는지는 아무도 모른다. UCPC 2018을 준비하던 ntopia는 여러 사람들에게 UCPC가 정확히 무엇의 줄임말인지 물어보았지만, 아무도 정확한 답을 제시해주지 못했다. ntopia가 들은 몇 가지 답을 아래에 적어보았다.

  • Union of Computer Programming Contest club contest
  • Union of Computer Programming contest Club contest
  • Union of Computer Programming contest club Contest
  • Union of Collegiate Programming Contest club contest
  • Union of Collegiate Programming contest Club contest
  • Union of Collegiate Programming contest club Contest
  • University Computer Programming Contest
  • University Computer Programming Club contest
  • University Computer Programming club Contest
  • University Collegiate Programming Contest
  • University CPC
  • ...

ntopia는 이렇게 다양한 답을 듣고는 UCPC가 무엇의 약자인지는 아무도 모른다고 결론내렸다. 적당히 슥삭해서 UCPC를 남길 수 있으면 모두 UCPC의 약자인 것이다!

문자열이 주어지면 이 문자열을 적절히 축약해서 "UCPC"로 만들 수 있는지 확인하는 프로그램을 만들어보자.

축약이라는 것은 문자열에서 임의의 문자들을 제거하는 행동을 뜻한다. 예를 들면, "apple"에서 a와 e를 지워 "ppl"로 만들 수 있고, "University Computer Programming Contest"에서 공백과 소문자를 모두 지워 "UCPC"로 만들 수 있다.

문자열을 비교할 때는 대소문자를 구분해 정확히 비교한다. 예를 들어 "UCPC"와 "UCpC"는 다른 문자열이다. 따라서 "University Computer programming Contest"를 "UCPC"로 축약할 수 있는 방법은 없다.

그나저나 UCPC는 정말 무엇의 약자였을까? 정확히 아시는 분은 제보 부탁드립니다.

입력

첫 번째 줄에 알파벳 대소문자, 공백으로 구성된 문자열이 주어진다. 문자열의 길이는 최대 1,000자이다. 문자열의 맨 앞과 맨 끝에 공백이 있는 경우는 없고, 공백이 연속해서 2번 이상 주어지는 경우도 없다.

출력

첫 번째 줄에 입력으로 주어진 문자열을 적절히 축약해 "UCPC"로 만들 수 있으면 "I love UCPC"를 출력하고, 만들 수 없으면 "I hate UCPC"를 출력한다.

예제 입력 1

Union of Computer Programming Contest club contest

예제 출력 1

I love UCPC

예제 입력 2

University Computer Programming

예제 출력 2

I hate UCPC

더보기

Solution

#include<stdio.h>
#include<string.h>

int main(void)
{
	int count=0, i;
	char sentence[1001]={'\0', };

	fgets(sentence,sizeof(sentence),stdin);

	for(i=0;i<strlen(sentence);i++)
		if(sentence[i]=='U')
		{
			count++;
			break;
		}
	for(;i<strlen(sentence);i++)
		if(sentence[i]=='C')
		{
			count++;
			break;
		}
	for(;i<strlen(sentence);i++)
		if(sentence[i]=='P')
		{
			count++;
			break;
		}
	for(;i<strlen(sentence);i++)
		if(sentence[i]=='C')
		{
			count++;
			break;
		}

	printf("I %s UCPC\n", count==4?"love":"hate");
	return 0;
}
728x90

광재는 전자기기 대여사업을 시작했다. 퇴근하기 전에 다음날 손님들에게 빌려줄 N개의 전자기기를 충전하려 한다. 사용 가능한 콘센트는 M개가 있고, 성능은 모두 동일하다.

전자기기들은 한 번에 하나의 콘센트에서만 충전이 가능하고, 충전에 필요한 시간은 2^k(0 ≤ k ≤ 15, k는 정수) 형태이다.

광재의 빠른 퇴근을 위해 모든 전자기기를 충전하기 위한 최소 시간이 얼마인지 알려주자.

입력

첫째 줄에 전자기기의 개수 N과 콘센트의 개수 M이 주어진다. (1 ≤ N ≤ 10,000, 1 ≤ M ≤ 10)

둘째 줄에 충전에 필요한 시간 ti를 나타내는 N개의 정수가 주어진다. (20 ​≤ t(i) ≤ 2^15, t(i) = 2^k (0 ≤ k ≤ 15, k는 정수))

출력

충전에 필요한 최소 시간을 출력한다.

예제 입력 1

5 2
1 4 4 8 1

예제 출력 1

9

더보기

Solution

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

int compare(const void *x,const void *y)
{
	return *(int *)x>*(int *)y?1:*(int *)x==*(int *)y?0:-1;
}

int main(void)
{
	int N, M, *t=NULL, *time=NULL, max=0;

	scanf("%d%d", &N, &M);
	t=(int *)malloc(N*sizeof(int));
	time=(int *)calloc(M,sizeof(int));

	for(int i=0;i<N;i++)
		scanf("%d", &t[i]);
	qsort((void *)t,(size_t)N,sizeof(int),compare);

	for(int i=N-1;i>=0;i--)
	{
		int min=0;
		for(int m=0;m<M;m++)
			min=time[min]>time[m]?m:min;
		time[min]+=t[i];
	}

	for(int m=0;m<M;m++)
		max=time[m]>max?time[m]:max;

	printf("%d\n", max);
	free(time);
	free(t);
	return 0;
}
728x90

그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.

입력

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.

출력

첫째 줄에 DFS를 수행한 결과를, 그 다음 줄에는 BFS를 수행한 결과를 출력한다. V부터 방문된 점을 순서대로 출력하면 된다.

예제 입력 1

4 5 1
1 2
1 3
1 4
2 4
3 4

예제 출력 1

1 2 4 3
1 2 3 4

예제 입력 2

5 5 3
5 4
5 2
1 2
3 4
3 1

예제 출력 2

3 1 2 5 4
3 1 4 2 5

예제 입력 3

1000 1 1000
999 1000

예제 출력 3

1000 999
1000 999

더보기

Solution

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

void DFS(bool **graph,bool *visited,int source,int N)
{
	visited[source]=true;
	for(int i=0;i<N;i++)
		if(!visited[i] && graph[source][i])
		{
			printf(" %d", i+1);
			DFS(graph,visited,i,N);
		}
}

void BFS(bool **graph,bool *visited,int source,int N)
{
	int *queue=(int *)malloc(N*sizeof(int)), front=0, rear=0;
	visited[source]=true;
	queue[rear++]=source;
	while(front<rear)
	{
		for(int i=0;i<N;i++)
			if(!visited[i] && graph[queue[front]][i])
			{
				queue[rear++]=i;
				visited[i]=true;
			}
		front++;
	}
	for(int i=0;i<rear;i++)
		printf("%d ", queue[i]+1);
	printf("\n");
	free(queue);
}

int main(void)
{
	int N, M, V, x, y;
	bool **graph=NULL, *visited=NULL;

	scanf("%d%d%d", &N, &M, &V);
	graph=(bool **)malloc(N*sizeof(bool *));
	for(int n=0;n<N;n++)
		graph[n]=(bool *)calloc(N,sizeof(bool));
	visited=(bool *)calloc(N,sizeof(bool));

	for(int m=0;m<M;m++)
	{
		scanf("%d%d", &x, &y);
		x--;
		y--;

		graph[x][y]=graph[y][x]=true;
	}

	V--;
	printf("%d", V+1);
	DFS(graph,visited,V,N);
	printf("\n");
	free(visited);
	visited=(bool *)calloc(N,sizeof(bool));

	BFS(graph,visited,V,N);

	free(visited);
	for(int n=0;n<N;n++)
		free(graph[n]);
	free(graph);
	return 0;
}
728x90

지민이는 N개의 원소를 포함하고 있는 양방향 순환 큐를 가지고 있다. 지민이는 이 큐에서 몇 개의 원소를 뽑아내려고 한다.

지민이는 이 큐에서 다음과 같은 3가지 연산을 수행할 수 있다.

  1. 첫 번째 원소를 뽑아낸다. 이 연산을 수행하면, 원래 큐의 원소가 a1, ..., ak이었던 것이 a2, ..., ak와 같이 된다.
  2. 왼쪽으로 한 칸 이동시킨다. 이 연산을 수행하면, a1, ..., ak가 a2, ..., ak, a1이 된다.
  3. 오른쪽으로 한 칸 이동시킨다. 이 연산을 수행하면, a1, ..., ak가 ak, a1, ..., ak-1이 된다.

큐에 처음에 포함되어 있던 수 N이 주어진다. 그리고 지민이가 뽑아내려고 하는 원소의 위치가 주어진다. (이 위치는 가장 처음 큐에서의 위치이다.) 이때, 그 원소를 주어진 순서대로 뽑아내는데 드는 2번, 3번 연산의 최솟값을 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 큐의 크기 N과 뽑아내려고 하는 수의 개수 M이 주어진다. N은 50보다 작거나 같은 자연수이고, M은 N보다 작거나 같은 자연수이다. 둘째 줄에는 지민이가 뽑아내려고 하는 수의 위치가 순서대로 주어진다. 위치는 1보다 크거나 같고, N보다 작거나 같은 자연수이다.

출력

첫째 줄에 문제의 정답을 출력한다.

예제 입력 1

10 3
1 2 3

예제 출력 1

0

예제 입력 2

10 3
2 9 5

예제 출력 2

8

예제 입력 3

32 6
27 16 30 11 6 23

예제 출력 3

59

예제 입력 4

10 10
1 6 3 2 7 9 8 4 10 5

예제 출력 4

14

더보기

Solution

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

int main(void)
{
	int N, M, element, current=0, count=0;
	bool *queue=NULL;

	scanf("%d%d", &N, &M);
	queue=(bool *)malloc(N*sizeof(bool));

	for(int n=0;n<N;n++)
		queue[n]=true;

	for(int m=0;m<M;m++)
	{
		int left=0, right=0;
		scanf("%d", &element);
		element--;

		if(element<current)
		{
			for(int k=current;k>element;k--)
				right+=queue[k];
			for(int k=0;k<element;k++)
				left+=queue[k];
			for(int k=current;k<N;k++)
				left+=queue[k];
		}
		else if(element>current)
		{
			for(int k=current;k<element;k++)
				right+=queue[k];
			for(int k=element;k<N;k++)
				left+=queue[k];
			for(int k=0;k<current;k++)
				left+=queue[k];
		}

		count+=left<right?left:right;
		queue[element]=false;
		current=element;
		while(!queue[current] && m!=N-1)
		{
			current++;
			current%=N;
		}
	}

	printf("%d\n", count);
	free(queue);
	return 0;
}
728x90

문제

김형택은 지금 몰래 Spider Solitaire(스파이더 카드놀이)를 하고 있다. 형택이는 이 게임을 이길 때도 있었지만, 질 때도 있었다. 누군가의 시선이 느껴진 형택이는 게임을 중단하고 코딩을 하기 시작했다. 의심을 피했다고 생각한 형택이는 다시 게임을 켰다. 그 때 형택이는 잠시 코딩을 하는 사이에 자신의 게임 실력이 눈에 띄게 향상된 것을 알았다.

이제 형택이는 앞으로의 모든 게임에서 지지 않는다. 하지만, 형택이는 게임 기록을 삭제 할 수 없기 때문에, 자신의 못하던 예전 기록이 현재 자신의 엄청난 실력을 증명하지 못한다고 생각했다.

게임 기록은 다음과 같이 생겼다.

  • 게임 횟수 : X
  • 이긴 게임 : Y (Z%)
  • Z는 형택이의 승률이고, 소수점은 버린다. 예를 들어, X=53, Y=47이라면, Z=88이다.

X와 Y가 주어졌을 때, 형택이가 게임을 최소 몇 번 더 해야 Z가 변하는지 구하는 프로그램을 작성하시오.

입력

각 줄에 정수 X와 Y가 주어진다.

출력

첫째 줄에 형택이가 게임을 최소 몇 판 더 해야하는지 출력한다. 만약 Z가 절대 변하지 않는다면 -1을 출력한다.

제한

  • 1 ≤ X ≤ 1,000,000,000
  • 0 ≤ Y ≤ X

예제 입력 1

10 8

예제 출력 1

1

예제 입력 2

100 80

예제 출력 2

6

예제 입력 3

47 47

예제 출력 3

-1

예제 입력 4

99000 0

예제 출력 4

1000

예제 입력 5

1000000000 470000000

예제 출력 5

19230770

더보기

Solution

#include<stdio.h>

int main(void)
{
	long int X, Y, Z, count=0, left=0, right=1000000000;

	scanf("%ld %ld", &X, &Y);

	Z=(Y*100)/X;
	if(Z>=99)
		count=-1;
	else
	{
		while(left<right-1)
		{
			count=(left+right)/2;

			if(((Y+count)*100)/(X+count)==Z)
				left=count;
			else
				right=count;
		}

		if(((Y+count)*100)/(X+count)==Z)
			count++;
	}

	printf("%ld\n", count);
	return 0;
}
728x90

문제

영문 문장을 입력받아 모음의 개수를 세는 프로그램을 작성하시오. 모음은 'a', 'e', 'i', 'o', 'u'이며 대문자 또는 소문자이다.

입력

입력은 여러 개의 테스트 케이스로 이루어져 있으며, 각 줄마다 영어 대소문자, ',', '.', '!', '?', 공백으로 이루어진 문장이 주어진다. 각 줄은 최대 255글자로 이루어져 있다.

입력의 끝에는 한 줄에 '#' 한 글자만이 주어진다.

출력

각 줄마다 모음의 개수를 세서 출력한다.

예제 입력 1

How are you today?
Quite well, thank you, how about yourself?
I live at number twenty four.
#

예제 출력 1

7
14
9

더보기

Solution

#include<stdio.h>
#include<string.h>

int main(void)
{
	char sentence[260]={'\0', }, end[3]={'#','\n'};

	fgets(sentence,sizeof(sentence),stdin);

	while(strcmp(sentence,end)!=0)
	{
		int count=0;

		for(int i=0;i<strlen(sentence);i++)
			switch(sentence[i])
			{
				case 'a':
				case 'e':
				case 'i':
				case 'o':
				case 'u':
				case 'A':
				case 'E':
				case 'I':
				case 'O':
				case 'U':
					count++;
					break;
				default:
					break;
			}

		printf("%d\n", count);
		fgets(sentence,sizeof(sentence),stdin);
	}

	return 0;
}
728x90

문제

수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이

N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

출력

첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.

둘째 줄에는 중앙값을 출력한다.

셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.

넷째 줄에는 범위를 출력한다.

예제 입력 1

5
1
3
8
-2
2

예제 출력 1

2
2
1
10

예제 입력 2

1
4000

예제 출력 2

4000
4000
4000
0

예제 입력 3

5
-1
-2
-3
-1
-2

예제 출력 3

-2
-2
-1
2

더보기

Solution

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

int ABS(int N)
{
	return N>0?N:-N;
}

int compare(const void *x,const void *y)
{
	return *(int *)x>*(int *)y?1:*(int *)x==*(int *)y?0:-1;
}

int main(void)
{
	int N, *sequence=NULL, pri=0, pri_count=0, sec, sec_count=0, count=1;
	double sum=0.0;

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

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

	sum/=(double)N;
	sum*=10.0;
	if(sum>=0 && (int)sum%10>4)
		sum+=10.0;
	else if(sum<0 && (int)abs(sum)%10>4)
		sum-=10.0;

	qsort((void *)sequence,(size_t)N,sizeof(int),compare);

	for(int n=1;n<N;n++)
		if(sequence[n]!=sequence[n-1])
		{
			if(count>pri_count)
			{
				pri=sequence[n-1];
				pri_count=count;
				sec_count=0;
			}
			else if(count==pri_count && count>sec_count)
			{
				sec=sequence[n-1];
				sec_count=count;
			}
			count=1;
		}
		else
			count++;
	if(count>pri_count)
	{
		pri=sequence[N-1];
		pri_count=count;
		sec_count=0;
	}
	else if(count==pri_count && count>sec_count)
	{
		sec=sequence[N-1];
		sec_count=count;
	}

	printf("%d\n%d\n%d\n%d\n", (int)sum/10, sequence[N/2], pri_count==sec_count?sec:pri, sequence[N-1]-sequence[0]);
	free(sequence);
	return 0;
}
728x90

+ Recent posts