코딩테스트 : 14889번 스타트와 링크
문제
오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이고 신기하게도 N은 짝수이다. 이제 N/2명으로 이루어진 스타트 팀과 링크 팀으로 사람들을 나눠야 한다.
BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 Sij는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 Sij의 합이다. Sij는 Sji와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 Sij와 Sji이다.
N=4이고, S가 아래와 같은 경우를 살펴보자.
i\j123412341 | 2 | 3 | |
4 | 5 | 6 | |
7 | 1 | 2 | |
3 | 4 | 5 |
예를 들어, 1, 2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.
- 스타트 팀: S12 + S21 = 1 + 4 = 5
- 링크 팀: S34 + S43 = 2 + 5 = 7
1, 3번이 스타트 팀, 2, 4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.
- 스타트 팀: S13 + S31 = 2 + 7 = 9
- 링크 팀: S24 + S42 = 6 + 4 = 10
축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1, 4번이 스타트 팀, 2, 3번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6이 되어서 차이가 0이 되고 이 값이 최소이다.
입력
첫째 줄에 N(4 ≤ N ≤ 20, N은 짝수)이 주어진다. 둘째 줄부터 N개의 줄에 S가 주어진다. 각 줄은 N개의 수로 이루어져 있고, i번 줄의 j번째 수는 Sij 이다. Sii는 항상 0이고, 나머지 Sij는 1보다 크거나 같고, 100보다 작거나 같은 정수이다.
출력
첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.
public class BackJoon
{
static int N = int.Parse(Console.ReadLine());
static int[,] board = new int[N+1, N+1];
static int minValue = int.MaxValue;
public static void Main()
{
// 보드까지 설정 완료
for (int i = 1; i < N+1; i++)
{
int[] row = Console.ReadLine().Split().Select(int.Parse).ToArray();
for (int j = 1; j < N+1; j++)
{
board[i, j] = row[j-1];
}
}
List<int> members = new List<int>();
List<int> remainMembers = new List<int>();
for (int i = 1; i < N + 1; i++)
{
remainMembers.Add(i);
}
Combination(members,1);
Console.WriteLine(minValue);
}
// 팀을 나누는 방법
// 팀을 나눴을 때 스코어를 구하는 방법.
// 스코어를 비교하는 방법
// 스코어를 먼저 구해보자 , 결국 N/2 개의 배열을 선언하고, 하나씩 돌아가면서 체크하면 된다.
public static int GetScore(List<int> members)
{
int score = 0;
for (int i = 0; i < members.Count; i++)
{
for (int j = 0; j < members.Count; j++)
{
score += board[members[i], members[j]];
}
}
return score;
}
// 팀을 나누는 방법
public static void Combination(List<int> members , int startIndex)
{
// 다 왔을 때 체크
if (members.Count == N / 2)
{
int selectedScore =GetScore(members);
List<int> remainMembers = new List<int>();
for (int i = 1; i < N + 1; i++)
{
if (!members.Contains(i)) remainMembers.Add(i);
}
int unSelectedScore = GetScore(remainMembers);
if ( Math.Abs(selectedScore - unSelectedScore) < minValue) minValue = Math.Abs(selectedScore - unSelectedScore);
return;
}
for (int i = startIndex; i < N + 1; i++)
{
members.Add(i);
Combination(members, i + 1);
members.RemoveAt(members.Count - 1);
}
}
}
처음에 순열처럼 풀다가 , 생각해보니 조합이라서 마지막에 코드를 조금 바꿨다.
코딩테스트 : 14888번 연산자 끼워넣기
문제
N개의 수로 이루어진 수열 A1, A2, ..., AN이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 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)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다.
출력
첫째 줄에 만들 수 있는 식의 결과의 최댓값을, 둘째 줄에는 최솟값을 출력한다. 연산자를 어떻게 끼워넣어도 항상 -10억보다 크거나 같고, 10억보다 작거나 같은 결과가 나오는 입력만 주어진다. 또한, 앞에서부터 계산했을 때, 중간에 계산되는 식의 결과도 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.
public class BackJoon
{
static int minValue = Int32.MaxValue;
static int maxValue = Int32.MinValue;
static int n = int.Parse(Console.ReadLine());
static int[] numbers = Console.ReadLine().Split().Select(int.Parse).ToArray();
static int[] operators = Console.ReadLine().Split().Select(int.Parse).ToArray();
public static void Main()
{
inserting(numbers[0], operators, 1);
Console.WriteLine(maxValue);
Console.WriteLine(minValue);
}
public static void inserting(int temp , int[] operators,int count )
{
if (count >= n)
{
if( temp < minValue ) minValue = temp;
if (temp > maxValue) maxValue = temp;
return;
}
int save = temp;
for (int i = 0; i < operators.Length; i++)
{
if (operators[i] > 0)
{
if (i == 0) temp += numbers[count];
else if (i == 1) temp -= numbers[count];
else if (i == 2) temp *= numbers[count];
else if (i == 3) temp /= numbers[count];
operators[i]--;
inserting(temp , operators,count+1 );
temp = save;
operators[i]++;
}
}
}
}
이 문제를 위의 문제보다 조금 쉽게 풀었다 .
항상 명심해야 하는 것 ! 백트래킹은 초기화 해 줘야 한다.
이제 백 트래킹도 한 문제만 남았다.
정답률이 조금 낮길래 미뤄두었는데 마지막문제로 풀고 , 백트래킹 관련해서 정리를 한 번 더 하면 될 것 같다.
'코딩테스트' 카테고리의 다른 글
백트래킹 문제 관련 정리 // 15649번 N과 M(1) , 9663번 N - Queen (0) | 2025.03.16 |
---|---|
2447번 별 찍기 -10, 11792번 하노이 탑 이동 순서 (0) | 2025.03.09 |
24060번 알고리즘 수업 병합 정렬 -1 , 4779번 칸토어 집합 (1) | 2025.03.03 |
1010번 다리 놓기 , 2018번 통계학 , 20920번 영단어 암기는 괴로워 (0) | 2025.02.26 |
비밀 코드 해독, 2884번 알람 시계, 가장 많이 받은 선물 (0) | 2025.02.23 |