1부터 N까지의 수로 이루어진 순열이 있다. 이때, 사전순으로 다음에 오는 순열을 구하는 프로그램을 작성하시오.

사전 순으로 가장 앞서는 순열은 오름차순으로 이루어진 순열이고, 가장 마지막에 오는 순열은 내림차순으로 이루어진 순열이다.

N = 3인 경우에 사전순으로 순열을 나열하면 다음과 같다.

  • 1, 2, 3
  • 1, 3, 2
  • 2, 1, 3
  • 2, 3, 1
  • 3, 1, 2
  • 3, 2, 1

입력

첫째 줄에 N(1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄에 순열이 주어진다.

출력

첫째 줄에 입력으로 주어진 순열의 다음에 오는 순열을 출력한다. 만약, 사전순으로 마지막에 오는 순열인 경우에는 -1을 출력한다.

예제 입력 1

4
1 2 3 4

예제 출력 1

1 2 4 3

예제 입력 2

5
5 4 3 2 1

예제 출력 2

-1

더보기

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, *permutation=NULL, index, *to_change=NULL, last;

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

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

	index=N-2;

	while(index>=0 && permutation[index]>permutation[index+1])
		index--;

	if(index<0 || N==1)
	{
		printf("-1\n");
		free(permutation);
		return 0;
	}

	to_change=(int *)malloc((N-index)*sizeof(int));
	for(int i=index;i<N;i++)
		to_change[i-index]=permutation[i];
	qsort((void *)to_change,(size_t)N-index,sizeof(int),compare);

	last=N-index-1;
	for(int i=index;i<N;i++)
		if(to_change[i-index]>permutation[index])
			last=to_change[i-index]<to_change[last]?i-index:last;

	int temp=to_change[last];
	for(int i=last;i>0;i--)
		to_change[i]=to_change[i-1];
	to_change[0]=temp;
	for(int i=index;i<N;i++)
		permutation[i]=to_change[i-index];

	for(int i=0;i<N;i++)
		printf("%d ", permutation[i]);
	printf("\n");

	free(permutation);
	free(to_change);
	return 0;
}
더보기

Solution

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

public class Main {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb=new StringBuilder();
		StringTokenizer st;

		int N=Integer.parseInt(br.readLine());
		int[] permutation=new int[N];
		
		st=new StringTokenizer(br.readLine());
		for(int i=0;i<N;i++)
			permutation[i]=Integer.parseInt(st.nextToken());
		
		int index=N-2;
		
		while(index>=0 && permutation[index]>permutation[index+1])
			index--;
		
		if(index<0 || N==1) {
			System.out.println(-1);
			return;
		}
		
		int[] to_change=new int[N-index];
		for(int i=index;i<N;i++)
			to_change[i-index]=permutation[i];
		Arrays.sort(to_change);
		
		int last=N-index-1;
		
		for(int i=index;i<N;i++)
			if(to_change[i-index]>permutation[index])
				last=to_change[i-index]<to_change[last]?i-index:last;
		
		int temp=to_change[last];
		for(int i=last;i>0;i--)
			to_change[i]=to_change[i-1];
		to_change[0]=temp;
		for(int i=index;i<N;i++)
			permutation[i]=to_change[i-index];
		
		for(int i=0;i<N;i++)
			sb.append(permutation[i]+" ");
		System.out.println(sb.toString());
	}
}

 

728x90

여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저의 배치는 다음 조건을 만족한다.

  • 쇠막대기는 자신보다 긴 쇠막대기 위에만 놓일 수 있다. - 쇠막대기를 다른 쇠막대기 위에 놓는 경우 완전히 포함되도록 놓되, 끝점은 겹치지 않도록 놓는다.
  • 각 쇠막대기를 자르는 레이저는 적어도 하나 존재한다.
  • 레이저는 어떤 쇠막대기의 양 끝점과도 겹치지 않는다. 

아래 그림은 위 조건을 만족하는 예를 보여준다. 수평으로 그려진 굵은 실선은 쇠막대기이고, 점은 레이저의 위치, 수직으로 그려진 점선 화살표는 레이저의 발사 방향이다.

이러한 레이저와 쇠막대기의 배치는 다음과 같이 괄호를 이용하여 왼쪽부터 순서대로 표현할 수 있다.

  1. 레이저는 여는 괄호와 닫는 괄호의 인접한 쌍 ‘( ) ’ 으로 표현된다. 또한, 모든 ‘( ) ’는 반드시 레이저를 표현한다.
  2. 쇠막대기의 왼쪽 끝은 여는 괄호 ‘ ( ’ 로, 오른쪽 끝은 닫힌 괄호 ‘) ’ 로 표현된다. 

위 예의 괄호 표현은 그림 위에 주어져 있다.

쇠막대기는 레이저에 의해 몇 개의 조각으로 잘려지는데, 위 예에서 가장 위에 있는 두 개의 쇠막대기는 각각 3개와 2개의 조각으로 잘려지고, 이와 같은 방식으로 주어진 쇠막대기들은 총 17개의 조각으로 잘려진다. 

쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 주어졌을 때, 잘려진 쇠막대기 조각의 총 개수를 구하는 프로그램을 작성하시오.

입력

한 줄에 쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 공백없이 주어진다. 괄호 문자의 개수는 최대 100,000이다. 

출력

잘려진 조각의 총 개수를 나타내는 정수를 한 줄에 출력한다.

예제 입력 1

()(((()())(())()))(())

예제 출력 1

17

예제 입력 2

(((()(()()))(())()))(()())

예제 출력 2

24

더보기

Solution

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

int main(void)
{
	char str[100001]={'\0', };
	int stack_count=0, count=0;

	scanf("%s", str);

	for(int i=0;i<strlen(str);i++)
		if(str[i]=='(')
			stack_count++;
		else
		{
			stack_count--;
			count+=str[i-1]=='('?stack_count:1;
		}

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

"전화번호가 뭐에요?"

"제 전화번호의 각 자리를 영어단어로 바꾸고, 철자를 잘 섞으면 OFFER EN NOXIOUS NEON OVERUSE가 나와요."

"예?"

"그리고 제 전화번호는 오름차순으로 정렬되어 있어요."

"..."

입력

첫 줄에 테스트케이스의 개수 T가 주어진다. 각 테스트케이스에는 상대방이 제시한 스트링 S가 주어진다. S는 영어 대문자로만 이루어져 있다.

1≤ T ≤ 100이고, S의 길이는 3 이상 2000 이하이다. 모든 테스트케이스에는 유일한 해답이 있다.

출력

각 줄에 테스트케이스 번호 x와 전화번호 y를 Case #x: y의 형태로 출력한다.

예제 입력 1

4
OZONETOWER
WEIGHFOXTOURIST
OURNEONFOE
ETHER

예제 출력 1

Case #1: 012
Case #2: 2468
Case #3: 114
Case #4: 3

힌트

ONE ONE ONE FOUR FOUR SIX SEVEN의 철자를 잘 배열하면 OFFERENNOXIOUSNEONOVERUSE가 나온다.


더보기

Solution

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

int main(void)
{
	int T;

	scanf("%d", &T);

	for(int t=1;t<=T;t++)
	{
		char S[2001]={'\0', };
		int alphabet[26]={0, }, number[10]={0, };

		scanf("%s", S);
		for(int s=0;s<strlen(S);s++)
			alphabet[S[s]-'A']++;

		if(alphabet['Z'-'A']>0)
		{
			number[0]=alphabet['Z'-'A'];
			alphabet['Z'-'A']-=number[0];
			alphabet['E'-'A']-=number[0];
			alphabet['R'-'A']-=number[0];
			alphabet['O'-'A']-=number[0];
		}
		if(alphabet['W'-'A']>0)
		{
			number[2]=alphabet['W'-'A'];
			alphabet['T'-'A']-=number[2];
			alphabet['W'-'A']-=number[2];
			alphabet['O'-'A']-=number[2];
		}
		if(alphabet['U'-'A']>0)
		{
			number[4]=alphabet['U'-'A'];
			alphabet['F'-'A']-=number[4];
			alphabet['O'-'A']-=number[4];
			alphabet['U'-'A']-=number[4];
			alphabet['R'-'A']-=number[4];
		}
		if(alphabet['X'-'A']>0)
		{
			number[6]=alphabet['X'-'A'];
			alphabet['S'-'A']-=number[6];
			alphabet['I'-'A']-=number[6];
			alphabet['X'-'A']-=number[6];
		}
		if(alphabet['G'-'A']>0)
		{
			number[8]=alphabet['G'-'A'];
			alphabet['E'-'A']-=number[8];
			alphabet['I'-'A']-=number[8];
			alphabet['G'-'A']-=number[8];
			alphabet['H'-'A']-=number[8];
			alphabet['T'-'A']-=number[8];

		}
		if(alphabet['T'-'A']>0)
		{
			number[3]=alphabet['T'-'A'];
			alphabet['T'-'A']-=number[3];
			alphabet['H'-'A']-=number[3];
			alphabet['R'-'A']-=number[3];
			alphabet['E'-'A']-=2*number[3];
		}
		if(alphabet['F'-'A']>0)
		{
			number[5]=alphabet['F'-'A'];
			alphabet['F'-'A']-=number[5];
			alphabet['I'-'A']-=number[5];
			alphabet['V'-'A']-=number[5];
			alphabet['E'-'A']-=number[5];
		}
		if(alphabet['S'-'A']>0)
		{
			number[7]=alphabet['S'-'A'];
			alphabet['S'-'A']-=number[7];
			alphabet['E'-'A']-=2*number[7];
			alphabet['V'-'A']-=number[7];
			alphabet['N'-'A']-=number[7];
		}
		if(alphabet['O'-'A']>0)
		{
			number[1]=alphabet['O'-'A'];
			alphabet['O'-'A']-=number[1];
			alphabet['N'-'A']-=number[1];
			alphabet['E'-'A']-=number[1];
		}
		if(alphabet['I'-'A']>0)
		{
			number[9]=alphabet['I'-'A'];
			alphabet['N'-'A']-=2*number[9];
			alphabet['I'-'A']-=number[9];
			alphabet['E'-'A']-=number[9];
		}

		printf("Case #%d: ", t);
		for(int i=0;i<10;i++)
			for(int j=0;j<number[i];j++)
				printf("%d", i);
		printf("\n");
	}

	return 0;
}
728x90

"전화번호가 뭐에요?"

"제 전화번호의 각 자리를 영어단어로 바꾸고, 철자를 잘 섞으면 OZONE TOWER가 나와요."

"예?"

"그리고 제 전화번호는 오름차순으로 정렬되어 있어요."

"..."

입력

첫 줄에 테스트케이스의 개수 T가 주어진다. 각 테스트케이스에는 상대방이 제시한 스트링 S가 주어진다. S는 영어 대문자로만 이루어져 있다.

1≤ T ≤ 100이고, S의 길이는 3 이상 20 이하이다. 모든 테스트케이스에는 유일한 해답이 있다.

출력

각 줄에 테스트케이스 번호 x와 전화번호 y를 Case #x: y의 형태로 출력한다.

예제 입력 1

4
OZONETOWER
WEIGHFOXTOURIST
OURNEONFOE
ETHER

예제 출력 1

Case #1: 012
Case #2: 2468
Case #3: 114
Case #4: 3

힌트

ZERO ONE TWO의 철자를 잘 배열하면 OZONETOWER가 나온다.


더보기

Solution

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

int main(void)
{
	int T;

	scanf("%d", &T);

	for(int t=1;t<=T;t++)
	{
		char S[21]={'\0', };
		int alphabet[26]={0, }, number[10]={0, };

		scanf("%s", S);
		for(int s=0;s<strlen(S);s++)
			alphabet[S[s]-'A']++;

		if(alphabet['Z'-'A']>0)
		{
			number[0]=alphabet['Z'-'A'];
			alphabet['Z'-'A']-=number[0];
			alphabet['E'-'A']-=number[0];
			alphabet['R'-'A']-=number[0];
			alphabet['O'-'A']-=number[0];
		}
		if(alphabet['W'-'A']>0)
		{
			number[2]=alphabet['W'-'A'];
			alphabet['T'-'A']-=number[2];
			alphabet['W'-'A']-=number[2];
			alphabet['O'-'A']-=number[2];
		}
		if(alphabet['U'-'A']>0)
		{
			number[4]=alphabet['U'-'A'];
			alphabet['F'-'A']-=number[4];
			alphabet['O'-'A']-=number[4];
			alphabet['U'-'A']-=number[4];
			alphabet['R'-'A']-=number[4];
		}
		if(alphabet['X'-'A']>0)
		{
			number[6]=alphabet['X'-'A'];
			alphabet['S'-'A']-=number[6];
			alphabet['I'-'A']-=number[6];
			alphabet['X'-'A']-=number[6];
		}
		if(alphabet['G'-'A']>0)
		{
			number[8]=alphabet['G'-'A'];
			alphabet['E'-'A']-=number[8];
			alphabet['I'-'A']-=number[8];
			alphabet['G'-'A']-=number[8];
			alphabet['H'-'A']-=number[8];
			alphabet['T'-'A']-=number[8];

		}
		if(alphabet['T'-'A']>0)
		{
			number[3]=alphabet['T'-'A'];
			alphabet['T'-'A']-=number[3];
			alphabet['H'-'A']-=number[3];
			alphabet['R'-'A']-=number[3];
			alphabet['E'-'A']-=2*number[3];
		}
		if(alphabet['F'-'A']>0)
		{
			number[5]=alphabet['F'-'A'];
			alphabet['F'-'A']-=number[5];
			alphabet['I'-'A']-=number[5];
			alphabet['V'-'A']-=number[5];
			alphabet['E'-'A']-=number[5];
		}
		if(alphabet['S'-'A']>0)
		{
			number[7]=alphabet['S'-'A'];
			alphabet['S'-'A']-=number[7];
			alphabet['E'-'A']-=2*number[7];
			alphabet['V'-'A']-=number[7];
			alphabet['N'-'A']-=number[7];
		}
		if(alphabet['O'-'A']>0)
		{
			number[1]=alphabet['O'-'A'];
			alphabet['O'-'A']-=number[1];
			alphabet['N'-'A']-=number[1];
			alphabet['E'-'A']-=number[1];
		}
		if(alphabet['I'-'A']>0)
		{
			number[9]=alphabet['I'-'A'];
			alphabet['N'-'A']-=2*number[9];
			alphabet['I'-'A']-=number[9];
			alphabet['E'-'A']-=number[9];
		}

		printf("Case #%d: ", t);
		for(int i=0;i<10;i++)
			for(int j=0;j<number[i];j++)
				printf("%d", i);
		printf("\n");
	}

	return 0;
}
728x90

루트가 있는 트리(rooted tree)가 주어지고, 그 트리 상의 두 정점이 주어질 때 그들의 가장 가까운 공통 조상(Nearest Common Anscestor)은 다음과 같이 정의됩니다.

  • 두 노드의 가장 가까운 공통 조상은, 두 노드를 모두 자손으로 가지면서 깊이가 가장 깊은(즉 두 노드에 가장 가까운) 노드를 말합니다.

예를 들어  15와 11를 모두 자손으로 갖는 노드는 4와 8이 있지만, 그 중 깊이가 가장 깊은(15와 11에 가장 가까운) 노드는 4 이므로 가장 가까운 공통 조상은 4가 됩니다.

루트가 있는 트리가 주어지고, 두 노드가 주어질 때 그 두 노드의 가장 가까운 공통 조상을 찾는 프로그램을 작성하세요

입력

첫 줄에 테스트 케이스의 개수 T가 주어집니다.

각 테스트 케이스마다, 첫째 줄에 트리를 구성하는 노드의 수 N이 주어집니다. (2 ≤ N ≤ 10,000)

그리고 그 다음 N-1개의 줄에 트리를 구성하는 간선 정보가 주어집니다. 한 간선 당 한 줄에 두 개의 숫자 A B 가 순서대로 주어지는데, 이는 A가 B의 부모라는 뜻입니다. (당연히 정점이 N개인 트리는 항상 N-1개의 간선으로 이루어집니다!) A와 B는 1 이상 N 이하의 정수로 이름 붙여집니다.

테스트 케이스의 마지막 줄에 가장 가까운 공통 조상을 구할 두 노드가 주어집니다.

출력

각 테스트 케이스 별로, 첫 줄에 입력에서 주어진 두 노드의 가장 가까운 공통 조상을 출력합니다.

예제 입력 1

2
16
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7
5
2 3
3 4
3 1
1 5
3 5

예제 출력 1

4
3

더보기

Solution

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

int main(void)
{
	int T;

	scanf("%d", &T);

	for(int t=0;t<T;t++)
	{
		int N, *parent=NULL, A, B, A_count=0, B_count=0, temp;

		scanf("%d", &N);
		parent=(int *)calloc(N+1,sizeof(int));

		for(int n=1;n<N;n++)
		{
			scanf("%d%d", &A, &B);
			parent[B]=A;
		}

		scanf("%d%d", &A, &B);

		temp=A;
		while(parent[temp]!=0)
		{
			A_count++;
			temp=parent[temp];
		}

		temp=B;
		while(parent[temp]!=0)
		{
			B_count++;
			temp=parent[temp];
		}

		if(A_count>B_count)
			for(int a=0;A_count-a>B_count;a++)
				A=parent[A];
		else if(B_count>A_count)
			for(int b=0;B_count-b>A_count;b++)
				B=parent[B];

		while(A!=B)
		{
			A=parent[A];
			B=parent[B];
		}

		printf("%d\n", A);
		free(parent);
	}

	return 0;
}
728x90

동주는 항상 혼자 노느라 심심하다. 하지만 혼자 놀기의 고수가 된 동주는 매일매일 게임을 개발하여 혼자놀기의 진수를 우리에게 보여준다. 어느 날 동주는 새로운 게임을 개발하였다. 바로 점수 따먹기라는 게임인데 그다지 재밌어 보이지는 않는다.

동주가 개발한 게임은 이렇다. 일단 N*M 행렬을 그린 다음, 각 칸에 -10,000 이상 10,000 이하의 정수를 하나씩 쓴다. 그런 다음 그 행렬의 부분행렬을 그려 그 안에 적힌 정수의 합을 구하는 게임이다.

동주가 혼자 재밌게 놀던 중 지나가는 당신을 보고 당신을 붙잡고 게임을 하자고 한다. 귀찮은 당신은 정수의 합이 최대가 되는 부분행렬을 구하여 빨리 동주에게서 벗어나고 싶다.

입력

첫째 줄에 N (1 < N < 200), M (1 < M < 200)이 주어진다. 그 다음 N개의 줄에 M개씩 행렬의 원소가 주어진다.

출력

첫째 줄에 최대의 합을 출력하라.

예제 입력 1

3 5
2 3 -21 -22 -23
5 6 -22 -23 -25
-22 -23 4 10 2

예제 출력 1

16

더보기

Solution

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

int main(void)
{
	int N, M, **matrix=NULL, max=-10000;

	scanf("%d%d", &N, &M);
	matrix=(int **)malloc((N+1)*sizeof(int *));
	for(int i=0;i<=N;i++)
		matrix[i]=(int *)calloc(M+1,sizeof(int));

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

	for(int i=0;i<=N;i++)
		for(int j=1;j<=M;j++)
			matrix[i][j]+=matrix[i][j-1];

	for(int j=0;j<=M;j++)
		for(int i=1;i<=N;i++)
			matrix[i][j]+=matrix[i-1][j];

	for(int i=1;i<=N;i++)
		for(int j=1;j<=M;j++)
			for(int k=0;k<i;k++)
				for(int l=0;l<j;l++)
					max=matrix[i][j]-matrix[k][j]-matrix[i][l]+matrix[k][l]>max?matrix[i][j]-matrix[k][j]-matrix[i][l]+matrix[k][l]:max;

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

개똥벌레 한 마리가 장애물(석순과 종유석)로 가득찬 동굴에 들어갔다. 동굴의 길이는 N미터이고, 높이는 H미터이다. (N은 짝수) 첫 번째 장애물은 항상 석순이고, 그 다음에는 종유석과 석순이 번갈아가면서 등장한다.

아래 그림은 길이가 14미터이고 높이가 5미터인 동굴이다. (예제 그림)

이 개똥벌레는 장애물을 피하지 않는다. 자신이 지나갈 구간을 정한 다음 일직선으로 지나가면서 만나는 모든 장애물을 파괴한다.

위의 그림에서 4번째 구간으로 개똥벌레가 날아간다면 파괴해야하는 장애물의 수는 총 여덟개이다. (4번째 구간은 길이가 3인 석순과 길이가 4인 석순의 중간지점을 말한다)

하지만, 첫 번째 구간이나 다섯 번째 구간으로 날아간다면 개똥벌레는 장애물 일곱개만 파괴하면 된다.

동굴의 크기와 높이, 모든 장애물의 크기가 주어진다. 이때, 개똥벌레가 파괴해야하는 장애물의 최솟값과 그러한 구간이 총 몇 개 있는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N과 H가 주어진다. N은 항상 짝수이다. (2 ≤ N ≤ 200,000, 2 ≤ H ≤ 500,000)

다음 N개 줄에는 장애물의 크기가 순서대로 주어진다. 장애물의 크기는 H보다 작은 양수이다.

출력

첫째 줄에 개똥벌레가 파괴해야 하는 장애물의 최솟값과 그러한 구간의 수를 공백으로 구분하여 출력한다.

예제 입력 1

6 7
1
5
3
3
5
1

예제 출력 1

2 3

예제 입력 2

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

예제 출력 2

7 2

더보기

Solution

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

int main(void)
{
	int N, H, *up=NULL, *down=NULL, obstacle, min=200000, min_count=1, stalagmite, stalactite=0;

	scanf("%d%d", &N, &H);
	up=(int *)calloc(H+1,sizeof(int));
	down=(int *)calloc(H+1,sizeof(int));

	stalagmite=N/2;
	for(int n=0;n<N;n++)
	{
		scanf("%d", &obstacle);
		if(n%2==0)
			down[obstacle]++;
		else
			up[obstacle]++;
	}

	for(int h=0;h<H;h++)
	{
		stalagmite-=down[h];
		stalactite+=up[H-h];

		if(stalagmite+stalactite<min)
		{
			min=stalagmite+stalactite;
			min_count=1;
		}
		else if(stalagmite+stalactite==min)
			min_count++;
	}

	printf("%d %d\n", min, min_count);
	free(up);
	free(down);
	return 0;
}
728x90

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루어진 정사각형 판 위에서 이뤄지는데, 게임 시작 전 일부 칸에는 1부터 9까지의 숫자 중 하나가 쓰여 있다.

나머지 빈 칸을 채우는 방식은 다음과 같다.

  1. 각각의 가로줄과 세로줄에는 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.
  2. 굵은 선으로 구분되어 있는 3x3 정사각형 안에도 1부터 9까지의 숫자가 한 번씩만 나타나야 한다.

위의 예의 경우, 첫째 줄에는 1을 제외한 나머지 2부터 9까지의 숫자들이 이미 나타나 있으므로 첫째 줄 빈칸에는 1이 들어가야 한다.

또한 위쪽 가운데 위치한 3x3 정사각형의 경우에는 3을 제외한 나머지 숫자들이 이미 쓰여있으므로 가운데 빈 칸에는 3이 들어가야 한다.

이와 같이 빈 칸을 차례로 채워 가면 다음과 같은 최종 결과를 얻을 수 있다.

게임 시작 전 스도쿠 판에 쓰여 있는 숫자들의 정보가 주어질 때 모든 빈 칸이 채워진 최종 모습을 출력하는 프로그램을 작성하시오.

입력

아홉 줄에 걸쳐 한 줄에 9개씩 게임 시작 전 스도쿠판 각 줄에 쓰여 있는 숫자가 한 칸씩 띄워서 차례로 주어진다. 스도쿠 판의 빈 칸의 경우에는 0이 주어진다. 스도쿠 판을 규칙대로 채울 수 없는 경우의 입력은 주어지지 않는다.

출력

모든 빈 칸이 채워진 스도쿠 판의 최종 모습을 아홉 줄에 걸쳐 한 줄에 9개씩 한 칸씩 띄워서 출력한다.

스도쿠 판을 채우는 방법이 여럿인 경우는 그 중 하나만을 출력한다.

제한

  • 12095번 문제에 있는 소스로 풀 수 있는 입력만 주어진다.
    • C++14: 80ms
    • Java: 292ms
    • PyPy3: 1172ms

예제 입력 1

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

예제 출력 1

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

더보기

Solution

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

bool found=false;

bool check_sudoku(int **square)
{
	for(int i=0;i<9;i++)
	{
		bool row[9]={false, }, col[9]={false, };
		int check_row=0, check_col=0;

		for(int j=0;j<9;j++)
		{
			if(square[i][j]==0 || square[j][i]==0)
				return false;

			if(row[square[i][j]-1])
				return false;
			else
				row[square[i][j]-1]=true;

			if(col[square[j][i]-1])
				return false;
			else
				col[square[j][i]-1]=true;
		}

		for(int j=0;j<9;j++)
		{
			check_row+=row[j];
			check_col+=col[j];
		}

		if(check_row!=9 || check_col!=9)
			return false;
	}

	for(int i=0;i<9;i+=3)
		for(int j=0;j<9;j+=3)
		{
			bool small_square[9]={false, };
			int check_small=0;

			for(int k=0;k<3;k++)
				for(int l=0;l<3;l++)
					if(small_square[square[i+k][j+l]-1])
						return false;
					else
						small_square[square[i+k][j+l]-1]=true;

			for(int k=0;k<9;k++)
				check_small+=small_square[k];

			if(check_small!=9)
				return false;
		}

	return true;
}

void sudoku(int **square,int **to_fill,int count)
{
	if(found)
		return;

	if(count==0)
	{
		if(check_sudoku(square))
		{
			for(int i=0;i<9;i++)
			{
				for(int j=0;j<9;j++)
					printf("%d ", square[i][j]);
				printf("\n");
			}
			found=true;
		}
		return;
	}
	else
	{
		int x=to_fill[count-1][0], y=to_fill[count-1][1];
		bool row[9]={false, }, col[9]={false, }, nine[9]={false, };

		for(int i=0;i<9;i++)
		{
			if(square[i][y]>0)
			{
				if(row[square[i][y]-1])
					return;
				else
					row[square[i][y]-1]=true;
			}
			if(square[x][i]>0)
			{
				if(col[square[x][i]-1])
					return;
				else
					col[square[x][i]-1]=true;
			}
		}
		for(int i=0;i<3;i++)
			for(int j=0;j<3;j++)
				if(square[x-x%3+i][y-y%3+j]>0)
				{
					if(nine[square[x-x%3+i][y-y%3+j]-1])
						return;
					else
						nine[square[x-x%3+i][y-y%3+j]-1]=true;
				}

		for(int i=0;i<9;i++)
		{
			if(!row[i] && !col[i] && !nine[i])
			{
				square[x][y]=i+1;
				sudoku(square,to_fill,count-1);
				square[x][y]=0;
			}
			if(found)
				return;
		}
		if(found)
			return;
	}
}

int main(void)
{
	int **square=(int **)malloc(9*sizeof(int *)), **to_fill=NULL, count=0, temp;

	for(int i=0;i<9;i++)
	{
		square[i]=(int  *)malloc(9*sizeof(int));

		for(int j=0;j<9;j++)
		{
			scanf("%d", &square[i][j]);
			count+=square[i][j]==0;
		}
	}

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

	temp=count;
	for(int i=8;i>=0;i--)
		for(int j=8;j>=0;j--)
			if(square[i][j]==0)
			{
				to_fill[--temp][0]=i;
				to_fill[temp][1]=j;
			}

	sudoku(square,to_fill,count);

	for(int i=0;i<count;i++)
		free(to_fill[i]);
	free(to_fill);
	for(int i=0;i<9;i++)
		free(square[i]);
	free(square);
	return 0;
}
728x90

+ Recent posts