바로 어제 최백준 조교가 방 열쇠를 주머니에 넣은 채 깜빡하고 서울로 가 버리는 황당한 상황에 직면한 조교들은, 702호에 새로운 보안 시스템을 설치하기로 하였다. 이 보안 시스템은 열쇠가 아닌 암호로 동작하게 되어 있는 시스템이다.

암호는 서로 다른 L개의 알파벳 소문자들로 구성되며 최소 한 개의 모음(a, e, i, o, u)과 최소 두 개의 자음으로 구성되어 있다고 알려져 있다. 또한 정렬된 문자열을 선호하는 조교들의 성향으로 미루어 보아 암호를 이루는 알파벳이 암호에서 증가하는 순서로 배열되었을 것이라고 추측된다. 즉, abc는 가능성이 있는 암호이지만 bac는 그렇지 않다.

새 보안 시스템에서 조교들이 암호로 사용했을 법한 문자의 종류는 C가지가 있다고 한다. 이 알파벳을 입수한 민식, 영식 형제는 조교들의 방에 침투하기 위해 암호를 추측해 보려고 한다. C개의 문자들이 모두 주어졌을 때, 가능성 있는 암호들을 모두 구하는 프로그램을 작성하시오.

입력

첫째 줄에 두 정수 L, C가 주어진다. (3 ≤ L ≤ C ≤ 15) 다음 줄에는 C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.

출력

각 줄에 하나씩, 사전식으로 가능성 있는 암호를 모두 출력한다.

예제 입력 1

4 6
a t c i s w

예제 출력 1

acis
acit
aciw
acst
acsw
actw
aist
aisw
aitw
astw
cist
cisw
citw
istw

더보기

Solution

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

void password(char *alphabet,int C,int L,int current,int last,char *list,int consonant,int vowel)
{
	if(current==L)
	{
		if(consonant>1 && vowel>0)
		{
			for(int l=0;l<L;l++)
				printf("%c", list[l]);
			printf("\n");
		}
		return;
	}
	for(int i=last+1;i<C;i++)
	{
		list[current]=alphabet[i];
		if(alphabet[i]=='a' || alphabet[i]=='e' || alphabet[i]=='i' || alphabet[i]=='o' || alphabet[i]=='u')
			password(alphabet,C,L,current+1,i,list,consonant,vowel+1);
		else
			password(alphabet,C,L,current+1,i,list,consonant+1,vowel);
	}
}

int main(void)
{
	int L, C;
	char *alphabet=NULL,  *list=NULL;

	scanf("%d%d", &L, &C);
	alphabet=(char *)malloc(C*sizeof(char));
	list=(char *)calloc(L,sizeof(char));

	for(int c=0;c<C;c++)
	{
		getchar();
		scanf("%c", &alphabet[c]);
	}

	for(int i=0;i<C;i++)
		for(int j=i+1;j<C;j++)
			if(alphabet[i]>alphabet[j])
			{
				char temp=alphabet[i];
				alphabet[i]=alphabet[j];
				alphabet[j]=temp;
			}

	password(alphabet,C,L,0,-1,list,0,0);
	free(alphabet);
	return 0;
}
더보기

Solution

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

public class Main {
	static char[] alphabet, list;
	static int L, C;
	static StringBuilder sb = new StringBuilder();
	
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st=new StringTokenizer(br.readLine());
		
		
		L=Integer.parseInt(st.nextToken());
		C=Integer.parseInt(st.nextToken());
		alphabet=new char[C];
		list=new char[L];
		
		st=new StringTokenizer(br.readLine());
		for(int i=0;i<C;i++)
			alphabet[i]=st.nextToken().charAt(0);
		
		Arrays.sort(alphabet);
		password(0,-1,0,0);
		System.out.print(sb.toString());
	}
	
	static void password(int current,int last,int consonant,int vowel) {
		if(current==L) {
			if(consonant>1 && vowel>0)
				sb.append(list).append("\n");
			return;
		}
		
		for(int i=last+1;i<C;i++) {
			list[current]=alphabet[i];
			if(alphabet[i]=='a' || alphabet[i]=='e' || alphabet[i]=='i' || alphabet[i]=='o' || alphabet[i]=='u')
				password(current+1,i,consonant,vowel+1);
			else
				password(current+1,i,consonant+1,vowel);
		}
	}
}

 

728x90

상근이가 1학년 때, 덧셈, 뺄셈을 매우 좋아했다. 상근이는 숫자가 줄 지어있는 것을 보기만 하면, 마지막 두 숫자 사이에 '='을 넣고, 나머지 숫자 사이에는 '+' 또는 '-'를 넣어 등식을 만들며 놀고 있다. 예를 들어, "8 3 2 4 8 7 2 4 0 8 8"에서 등식 "8+3-2-4+8-7-2-4-0+8=8"을 만들 수 있다.

상근이는 올바른 등식을 만들려고 한다. 상근이는 아직 학교에서 음수를 배우지 않았고, 20을 넘는 수는 모른다. 따라서, 왼쪽부터 계산할 때, 중간에 나오는 수가 모두 0 이상 20 이하이어야 한다. 예를 들어, "8+3+2-4-8-7+2+4+0+8=8"은 올바른 등식이지만, 8+3+2-4-8-7이 음수이기 때문에, 상근이가 만들 수 없는 등식이다.

숫자가 주어졌을 때, 상근이가 만들 수 있는 올바른 등식의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 숫자의 개수 N이 주어진다. (3 ≤ N ≤ 100) 둘째 줄에는 0 이상 9 이하의 정수 N개가 공백으로 구분해 주어진다.

출력

첫째 줄에 상근이가 만들 수 있는 올바른 등식의 개수를 출력한다. 이 값은 2^63-1 이하이다.

예제 입력 1

11
8 3 2 4 8 7 2 4 0 8 8

예제 출력 1

10

예제 입력 2

40
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1

예제 출력 2

7069052760

힌트

예제 1의 경우 다음과 같이 10가지 방법이 있다.

  • 8+3-2-4+8-7-2-4-0+8=8
  • 8+3-2-4+8-7-2-4+0+8=8
  • 8+3+2+4-8-7+2-4-0+8=8
  • 8+3+2+4-8-7+2-4+0+8=8
  • 8+3+2-4+8-7+2+4-0-8=8
  • 8+3+2-4+8-7+2+4+0-8=8
  • 8-3+2+4-8+7+2+4-0-8=8
  • 8-3+2+4-8+7+2+4+0-8=8
  • 8-3+2-4+8+7+2-4-0-8=8
  • 8-3+2-4+8+7+2-4+0-8=8

더보기

Solution

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

int main(void)
{
	int N, *number=NULL;
	unsigned long long int **count=NULL;

	scanf("%d", &N);
	number=(int *)malloc(N*sizeof(int));
	count=(unsigned long long int **)malloc(N*sizeof(unsigned long long int *));
	for(int n=0;n<N;n++)
		count[n]=(unsigned long long int *)calloc(21,sizeof(unsigned long long int));

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

	count[0][number[0]]=1;
	for(int i=1;i<N-1;i++)
		for(int j=0;j<21;j++)
		{
			if(j+number[i]<21)
				count[i][j+number[i]]+=count[i-1][j];
			if(j-number[i]>=0)
				count[i][j-number[i]]+=count[i-1][j];
		}

	printf("%llu\n", count[N-2][number[N-1]]);
	for(int n=0;n<N;n++)
		free(count[n]);
	free(count);
	free(number);
	return 0;
}
728x90

숫자의 신은 여러명이 있지만, 그 중에 자연수의 신은 오세준이다. 오세준은 자연수의 신으로 오래오래 살다가 어느 날 음수의 신과 전쟁을 하게 되었다. 오세준은 음수의 신 이다솜을 이기기위해서 큰 숫자를 만들기로 했다.

오세준은 지금 K개의 자연수를 가지고 있다. 오세준은 K개의 수 중에 정확하게 N개의 수를 뽑아내서 그 수를 붙여서 만들 수 있는 수중에 가장 큰 수를 만들고자 한다. 같은 수를 여러 번 이용해도 된다. 단, 모든 수는 적어도 한 번은 이용되어야 한다.

오세준이 현재 가지고 있는 K개의 수가 주어졌을 때, 이 수를 적어도 한 번 이상 이용해서 만들 수 있는 수 중에 가장 큰 수를 출력하는 프로그램을 작성하시오.

예를 들어 지금 오세준이 2, 3, 7 이라는 3개의 수를 가지고 있고, 4개의 수를 뽑아야 한다면, 7732를 만들면 가장 큰 수가 된다.

입력

첫째 줄에 K와 N이 공백을 사이에 두고 주어진다. K와 N은 각각 50보다 작거나 같은 자연수이고, N은 K보다 크거나 같다. 둘째 줄에는 K개의 수가 한 줄에 하나씩 주어진다. 각 수는 1,000,000,000보다 작거나 같은 자연수이다. 이 수는 중복되어 들어올 수 있다. 만약 중복되어서 들어오는 경우에는 각 수가 적어도 입력으로 주어진 만큼 이용되어야 한다는 소리다.

출력

N개의 수를 뽑아서 연결해서 만들 수 있는 가장 큰 수를 출력한다.

예제 입력 1

3 3
3
2
7

예제 출력 1

732

예제 입력 2

2 4
4
7

예제 출력 2

7774

예제 입력 3

3 4
1
10
100

예제 출력 3

110100100

예제 입력 4

4 9
4
4
4
4

예제 출력 4

444444444

예제 입력 5

3 3
1
1
2

예제 출력 5

211

더보기

Solution

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

int compare(char *a,char *b)
{
	int len_a=strlen(a), len_b=strlen(b);
	char *a_first=NULL, *b_first=NULL;

	if(len_a<len_b)
	{
		for(int i=0;i<len_b;i++)
			if(a[i%len_a]<b[i])
				return 1;
			else if(a[i%len_a]>b[i])
				return -1;
	}
	else
	{
		for(int i=0;i<len_a;i++)
			if(a[i]<b[i%len_b])
				return 1;
			else if(a[i]>b[i%len_b])
				return -1;
	}

	a_first=(char *)calloc(len_a+len_b,sizeof(char));
	strcpy(a_first,a);
	strcat(a_first,b);
	b_first=(char *)calloc(len_a+len_b,sizeof(char));
	strcpy(b_first,b);
	strcat(b_first,a);

	for(int i=0;i<len_a+len_b;i++)
		if(a_first[i]<b_first[i])
		{
			free(a_first);
			free(b_first);
			return 1;
		}
		else if(a_first[i]>b_first[i])
		{
			free(a_first);
			free(b_first);
			return -1;
		}

	free(a_first);
	free(b_first);
	return 1;
}

int main(void)
{
	int N, K, num, max=0;
	char **list=NULL;

	scanf("%d%d", &K, &N);
	list=(char **)malloc(N*sizeof(char *));
	for(int n=0;n<N;n++)
		list[n]=(char *)calloc(11,sizeof(char));

	for(int k=0;k<K;k++)
	{
		scanf("%d", &num);
		max=num>max?num:max;
		sprintf(list[k],"%d", num);
	}
	for(int i=K;i<N;i++)
		sprintf(list[i],"%d", max);

	for(int i=0;i<N;i++)
		for(int j=i+1;j<N;j++)
			if(compare(list[i],list[j])>0)
			{
				char temp[11]={'\0', };
				strcpy(temp,list[i]);
				strcpy(list[i],list[j]);
				strcpy(list[j],temp);
			}

	for(int n=0;n<N;n++)
		printf("%s", list[n]);
	printf("\n");

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

음이 아닌 정수가 N개 들어있는 리스트가 주어졌을 때, 리스트에 포함된 수를 나열하여 만들 수 있는 가장 큰 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 리스트에 포함된 수가 주어진다. 수는 공백으로 구분되어져 있고, 1,000,000,000보다 작거나 같은 음이 아닌 정수 이다. 0을 제외한 나머지 수는 0으로 시작하지 않으며, 0이 주어지는 경우 0 하나가 주어진다.

출력

리스트에 포함된 수를 나열하여 만들 수 있는 가장 큰 수를 출력한다. 수는 0으로 시작하면 안되며, 0이 정답인 경우 0 하나를 출력해야 한다.

예제 입력 1

5
3 30 34 5 9

예제 출력 1

9534330

예제 입력 2

5
0 0 0 0 1

예제 출력 2

10000

더보기

Solution

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

int compare(char *a,char *b)
{
	int len_a=strlen(a), len_b=strlen(b);
	char *a_first=NULL, *b_first=NULL;

	if(len_a<len_b)
	{
		for(int i=0;i<len_b;i++)
			if(a[i%len_a]<b[i])
				return 1;
			else if(a[i%len_a]>b[i])
				return -1;
	}
	else
	{
		for(int i=0;i<len_a;i++)
			if(a[i]<b[i%len_b])
				return 1;
			else if(a[i]>b[i%len_b])
				return -1;
	}

	a_first=(char *)calloc(len_a+len_b,sizeof(char));
	strcpy(a_first,a);
	strcat(a_first,b);
	b_first=(char *)calloc(len_a+len_b,sizeof(char));
	strcpy(b_first,b);
	strcat(b_first,a);

	for(int i=0;i<len_a+len_b;i++)
		if(a_first[i]<b_first[i])
		{
			free(a_first);
			free(b_first);
			return 1;
		}
		else if(a_first[i]>b_first[i])
		{
			free(a_first);
			free(b_first);
			return -1;
		}

	free(a_first);
	free(b_first);
	return 1;
}

int main(void)
{
	int N;
	char **list=NULL;

	scanf("%d", &N);
	list=(char **)malloc(N*sizeof(char *));
	for(int n=0;n<N;n++)
	{
		list[n]=(char *)calloc(11,sizeof(char));
		scanf("%s", list[n]);
	}

	for(int i=0;i<N;i++)
		for(int j=i+1;j<N;j++)
			if(compare(list[i],list[j])>0)
			{
				char temp[11]={'\0', };
				strcpy(temp,list[i]);
				strcpy(list[i],list[j]);
				strcpy(list[j],temp);
			}

	if(list[0][0]=='0')
		printf("0\n");
	else
	{
		for(int n=0;n<N;n++)
			printf("%s", list[n]);
		printf("\n");
	}

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

N개의 수로 이루어진 수열 A(1), A(2), ..., A(N)이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 N-1개의 연산자가 주어진다. 연산자는 덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷)으로만 이루어져 있다.

우리는 수와 수 사이에 연산자를 하나씩 넣어서, 수식을 하나 만들 수 있다. 이때, 주어진 수의 순서를 바꾸면 안 된다.

예를 들어, 6개의 수로 이루어진 수열이 1, 2, 3, 4, 5, 6이고, 주어진 연산자가 덧셈(+) 2개, 뺄셈(-) 1개, 곱셈(×) 1개, 나눗셈(÷) 1개인 경우에는 총 60가지의 식을 만들 수 있다. 예를 들어, 아래와 같은 식을 만들 수 있다.

  • 1+2+3-4×5÷6
  • 1÷2+3+4-5×6
  • 1+2÷3×4-5+6
  • 1÷2×3-4+5+6

식의 계산은 연산자 우선 순위를 무시하고 앞에서부터 진행해야 한다. 또, 나눗셈은 정수 나눗셈으로 몫만 취한다. 음수를 양수로 나눌 때는 C++14의 기준을 따른다. 즉, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다. 이에 따라서, 위의 식 4개의 결과를 계산해보면 아래와 같다.

  • 1+2+3-4×5÷6 = 1
  • 1÷2+3+4-5×6 = 12
  • 1+2÷3×4-5+6 = 5
  • 1÷2×3-4+5+6 = 7

N개의 수와 N-1개의 연산자가 주어졌을 때, 만들 수 있는 식의 결과가 최대인 것과 최소인 것을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A(1), A(2), ..., A(N)이 주어진다. (1 ≤ A(i) ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다. 

출력

첫째 줄에 만들 수 있는 식의 결과의 최댓값을, 둘째 줄에는 최솟값을 출력한다. 연산자를 어떻게 끼워넣어도 항상 -10억보다 크거나 같고, 10억보다 작거나 같은 결과가 나오는 입력만 주어진다. 또한, 앞에서부터 계산했을 때, 중간에 계산되는 식의 결과도 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.

예제 입력 1

2
5 6
0 0 1 0

예제 출력 1

30
30

예제 입력 2

3
3 4 5
1 0 1 0

예제 출력 2

35
17

예제 입력 3

6
1 2 3 4 5 6
2 1 1 1

예제 출력 3

54
-24

힌트

세 번째 예제의 경우에 다음과 같은 식이 최댓값/최솟값이 나온다.

  • 최댓값: 1-2÷3+4+5×6
  • 최솟값: 1+2+3÷4-5×6

더보기

Solution

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

int max(int *A,int plus,int minus,int multiply,int divide,int index,int N,int current)
{
	int max_num=-2000000000;

	if(index==N-1)
	{
		if(plus>0)
			return current+A[index];
		else if(minus>0)
			return current-A[index];
		else if(multiply>0)
			return current*A[index];
		else
			return current/A[index];
	}

	if(plus>0)
	{
		int cal=max(A,plus-1,minus,multiply,divide,index+1,N,current+A[index]);
		max_num=cal>max_num?cal:max_num;
	}
	if(minus>0)
	{
		int cal=max(A,plus,minus-1,multiply,divide,index+1,N,current-A[index]);
		max_num=cal>max_num?cal:max_num;
	}
	if(multiply>0)
	{
		int cal=max(A,plus,minus,multiply-1,divide,index+1,N,current*A[index]);
		max_num=cal>max_num?cal:max_num;
	}
	if(divide>0)
	{
		int cal=max(A,plus,minus,multiply,divide-1,index+1,N,current/A[index]);
		max_num=cal>max_num?cal:max_num;
	}

	return max_num;
}

int min(int *A,int plus,int minus,int multiply,int divide,int index,int N,int current)
{
	int min_num=2000000000;

	if(index==N-1)
	{
		if(plus>0)
			return current+A[index];
		else if(minus>0)
			return current-A[index];
		else if(multiply>0)
			return current*A[index];
		else
			return current/A[index];
	}

	if(plus>0)
	{
		int cal=min(A,plus-1,minus,multiply,divide,index+1,N,current+A[index]);
		min_num=cal<min_num?cal:min_num;
	}
	if(minus>0)
	{
		int cal=min(A,plus,minus-1,multiply,divide,index+1,N,current-A[index]);
		min_num=cal<min_num?cal:min_num;
	}
	if(multiply>0)
	{
		int cal=min(A,plus,minus,multiply-1,divide,index+1,N,current*A[index]);
		min_num=cal<min_num?cal:min_num;
	}
	if(divide>0)
	{
		int cal=min(A,plus,minus,multiply,divide-1,index+1,N,current/A[index]);
		min_num=cal<min_num?cal:min_num;
	}

	return min_num;
}

int main(void)
{
	int N, *A=NULL, plus, minus, multiply, divide;

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

	for(int i=0;i<N;i++)
		scanf("%d", &A[i]);
	scanf("%d%d%d%d", &plus, &minus, &multiply, &divide);

	printf("%d\n%d\n", max(A,plus,minus,multiply,divide,1,N,A[0]), min(A,plus,minus,multiply,divide,1,N,A[0]));
	free(A);
	return 0;
}
728x90

오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이고 신기하게도 N은 짝수이다. 이제 N/2명으로 이루어진 스타트 팀과 링크 팀으로 사람들을 나눠야 한다.

BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 S(ij)는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 S(ij)의 합이다. S(ij)는 S(ji)와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 S(ij)와 S(ji)이다.

N=4이고, S가 아래와 같은 경우를 살펴보자.

i/j 1 2 3 4
1   1 2 3
2 4   5 6
3 7 1   2
4 3 4 5  

예를 들어, 1, 2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S(12) + S(21) = 1 + 4 = 5
  • 링크 팀: S(34) + S(43) = 2 + 5 = 7

1, 3번이 스타트 팀, 2, 4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S(13) + S(31) = 2 + 7 = 9
  • 링크 팀: S(24) + S(42) = 6 + 4 = 10

축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1, 4번이 스타트 팀, 2, 3번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6이 되어서 차이가 0이 되고 이 값이 최소이다.

입력

첫째 줄에 N(4 ≤ N ≤ 20, N은 짝수)이 주어진다. 둘째 줄부터 N개의 줄에 S가 주어진다. 각 줄은 N개의 수로 이루어져 있고, i번 줄의 j번째 수는 S(ij) 이다. S(ii)는 항상 0이고, 나머지 S(ij)는 1보다 크거나 같고, 100보다 작거나 같은 정수이다.

출력

첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.

예제 입력 1

4
0 1 2 3
4 0 5 6
7 1 0 2
3 4 5 0

예제 출력 1

0

예제 입력 2

6
0 1 2 3 4 5
1 0 2 3 4 5
1 2 0 3 4 5
1 2 3 0 4 5
1 2 3 4 0 5
1 2 3 4 5 0

예제 출력 2

2

예제 입력 3

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

예제 출력 3

1

힌트

예제 2의 경우에 (1, 3, 6), (2, 4, 5)로 팀을 나누면 되고, 예제 3의 경우에는 (1, 2, 4, 5), (3, 6, 7, 8)로 팀을 나누면 된다.


더보기

Solution

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

int divide_team(int **S,bool *selected,int N,int current,int count)
{
	if(current==N)
		if(count*2==N)
		{
			int start=0, link=0;

			for(int n=0;n<N;n++)
				if(selected[n])
				{
					for(int i=n+1;i<N;i++)
						if(selected[i])
							start+=S[i][n]+S[n][i];
				}
				else
				{
					for(int i=n+1;i<N;i++)
						if(!selected[i])
							link+=S[i][n]+S[n][i];
				}

			return start-link>0?start-link:link-start;
		}
		else
			return 100000000;
	if(count*2<N)
	{
		int start, link;

		link=divide_team(S,selected,N,current+1,count);
		selected[current]=true;
		start=divide_team(S,selected,N,current+1,count+1);
		selected[current]=false;

		return link<start?link:start;
	}
	else if(count*2==N)
		return divide_team(S,selected,N,N,count);
	else
		return 100000000;
}
int main(void)
{
	int N, **S=NULL;
	bool *selected=NULL;

	scanf("%d", &N);
	S=(int **)malloc(N*sizeof(int *));
	for(int i=0;i<N;i++)
	{
		S[i]=(int *)malloc(N*sizeof(int));
		for(int j=0;j<N;j++)
			scanf("%d", &S[i][j]);
	}
	selected=(bool *)calloc(N,sizeof(bool));

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

가중치 없는 방향 그래프 G가 주어졌을 때, 모든 정점 (i, j)에 대해서, i에서 j로 가는 경로가 있는지 없는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정점의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄부터 N개 줄에는 그래프의 인접 행렬이 주어진다. i번째 줄의 j번째 숫자가 1인 경우에는 i에서 j로 가는 간선이 존재한다는 뜻이고, 0인 경우는 없다는 뜻이다. i번째 줄의 i번째 숫자는 항상 0이다.

출력

총 N개의 줄에 걸쳐서 문제의 정답을 인접행렬 형식으로 출력한다. 정점 i에서 j로 가는 경로가 있으면 i번째 줄의 j번째 숫자를 1로, 없으면 0으로 출력해야 한다.

예제 입력 1

3
0 1 0
0 0 1
1 0 0

예제 출력 1

1 1 1
1 1 1
1 1 1

예제 입력 2

7
0 0 0 1 0 0 0
0 0 0 0 0 0 1
0 0 0 0 0 0 0
0 0 0 0 1 1 0
1 0 0 0 0 0 0
0 0 0 0 0 0 1
0 0 1 0 0 0 0

예제 출력 2

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

더보기

Solution

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

int main(void)
{
	int N, **G=NULL;

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

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

	for(int i=0;i<N;i++)
		for(int j=0;j<N;j++)
		{
			if(G[i][j])
				for(int k=0;k<N;k++)
					if(G[k][i])
						G[k][j]=1;
			if(G[j][i])
				for(int k=0;k<N;k++)
					if(G[k][j])
						G[k][i]=1;
		}

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

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸, 왼쪽에서부터 c번째 칸을 의미한다. r과 c는 1부터 시작한다.

이 도시에 사는 사람들은 치킨을 매우 좋아한다. 따라서, 사람들은 "치킨 거리"라는 말을 주로 사용한다. 치킨 거리는 집과 가장 가까운 치킨집 사이의 거리이다. 즉, 치킨 거리는 집을 기준으로 정해지며, 각각의 집은 치킨 거리를 가지고 있다. 도시의 치킨 거리는 모든 집의 치킨 거리의 합이다.

임의의 두 칸 (r1, c1)과 (r2, c2) 사이의 거리는 |r1-r2| + |c1-c2|로 구한다.

예를 들어, 아래와 같은 지도를 갖는 도시를 살펴보자.

0 2 0 1 0
1 0 1 0 0
0 0 0 0 0
0 0 0 1 1
0 0 0 1 2

0은 빈 칸, 1은 집, 2는 치킨집이다.

(2, 1)에 있는 집과 (1, 2)에 있는 치킨집과의 거리는 |2-1| + |1-2| = 2, (5, 5)에 있는 치킨집과의 거리는 |2-5| + |1-5| = 7이다. 따라서, (2, 1)에 있는 집의 치킨 거리는 2이다.

(5, 4)에 있는 집과 (1, 2)에 있는 치킨집과의 거리는 |5-1| + |4-2| = 6, (5, 5)에 있는 치킨집과의 거리는 |5-5| + |4-5| = 1이다. 따라서, (5, 4)에 있는 집의 치킨 거리는 1이다.

이 도시에 있는 치킨집은 모두 같은 프랜차이즈이다. 프렌차이즈 본사에서는 수익을 증가시키기 위해 일부 치킨집을 폐업시키려고 한다. 오랜 연구 끝에 이 도시에서 가장 수익을 많이 낼 수 있는  치킨집의 개수는 최대 M개라는 사실을 알아내었다.

도시에 있는 치킨집 중에서 최대 M개를 고르고, 나머지 치킨집은 모두 폐업시켜야 한다. 어떻게 고르면, 도시의 치킨 거리가 가장 작게 될지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N(2 ≤ N ≤ 50)과 M(1 ≤ M ≤ 13)이 주어진다.

둘째 줄부터 N개의 줄에는 도시의 정보가 주어진다.

도시의 정보는 0, 1, 2로 이루어져 있고, 0은 빈 칸, 1은 집, 2는 치킨집을 의미한다. 집의 개수는 2N개를 넘지 않으며, 적어도 1개는 존재한다. 치킨집의 개수는 M보다 크거나 같고, 13보다 작거나 같다.

출력

첫째 줄에 폐업시키지 않을 치킨집을 최대 M개를 골랐을 때, 도시의 치킨 거리의 최솟값을 출력한다.

예제 입력 1

5 3
0 0 1 0 0
0 0 2 0 1
0 1 2 0 0
0 0 1 0 0
0 0 0 0 2

예제 출력 1

5

예제 입력 2

5 2
0 2 0 1 0
1 0 1 0 0
0 0 0 0 0
2 0 0 1 1
2 2 0 1 2

예제 출력 2

10

예제 입력 3

5 1
1 2 0 0 0
1 2 0 0 0
1 2 0 0 0
1 2 0 0 0
1 2 0 0 0

예제 출력 3

11

예제 입력 4

5 1
1 2 0 2 1
1 2 0 2 1
1 2 0 2 1
1 2 0 2 1
1 2 0 2 1

예제 출력 4

32

더보기

Solution

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

int abs(int x)
{
	return x>0?x:-x;
}

int chicken_distance(int **chicken,int **house,int chicken_count,int house_count,int M,int current,int left)
{
	if(left==0 || chicken_count==M)
	{
		int sum=0;

		for(int i=0;i<house_count;i++)
		{
			int distance=99999999;

			for(int j=0;j<chicken_count;j++)
				if(chicken[j][0]!=-1 && chicken[j][1]!=-1)
					distance=abs(house[i][0]-chicken[j][0])+abs(house[i][1]-chicken[j][1])<distance?abs(house[i][0]-chicken[j][0])+abs(house[i][1]-chicken[j][1]):distance;

			sum+=distance;
		}

		return sum;
	}

	if(current+left<chicken_count)
	{
		int best=999999999;
		for(int i=current+1;i<chicken_count;i++)
		{
			int x=chicken[i][0], y=chicken[i][1];
			chicken[i][0]=chicken[i][1]=-1;

			int next=chicken_distance(chicken,house,chicken_count,house_count,M,i,left-1);
			best=next<best?next:best;
			chicken[i][0]=x;
			chicken[i][1]=y;
		}

		return best;
	}

	return 999999999;
}

int main(void)
{
	int N, M, **chicken=NULL, **map=NULL, **house=NULL, chicken_count=0, house_count=0;

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

	for(int i=0;i<N;i++)
		for(int j=0;j<N;j++)
		{
			scanf("%d", &map[i][j]);
			chicken_count+=map[i][j]==2;
			house_count+=map[i][j]==1;
		}

	chicken=(int **)malloc(chicken_count*sizeof(int *));
	for(int i=0;i<chicken_count;i++)
		chicken[i]=(int *)malloc(2*sizeof(int));

	chicken_count=0;
	for(int i=0;i<N;i++)
		for(int j=0;j<N;j++)
			if(map[i][j]==2)
			{
				chicken[chicken_count][0]=i;
				chicken[chicken_count][1]=j;
				chicken_count++;
			}

	house=(int **)malloc(house_count*sizeof(int *));
	for(int i=0;i<house_count;i++)
		house[i]=(int *)malloc(2*sizeof(int));

	house_count=0;
	for(int i=0;i<N;i++)
		for(int j=0;j<N;j++)
			if(map[i][j]==1)
			{
				house[house_count][0]=i;
				house[house_count][1]=j;
				house_count++;
			}

	printf("%d\n", chicken_distance(chicken,house,chicken_count,house_count,M,-1,chicken_count-M));
	for(int i=0;i<house_count;i++)
		free(house[i]);
	free(house);
	for(int i=0;i<chicken_count;i++)
		free(chicken[i]);
	free(chicken);
	for(int i=0;i<N;i++)
		free(map[i]);
	free(map);
	return 0;
}
728x90

+ Recent posts