본문 바로가기
Algorithm/🏫assignment

# Card Game

by yewoneeee 2022. 10. 29.

# 문제

 

# 입력 및 출력

 

# 풀이

처음에 풀 땐 dp[i][j]를 만들어서 i부터 j까지의 카드중에서 맨 앞과 맨 뒤 중 어떤 값을 선택할지를 dp에 저장해뒀었다.

근데 이렇게 하면 문제점이 가장 큰 값을 선택하기 때문에 앞에 작은 값이 오더라도 계산 결과는 크게 나오는 경우를 처리하지 못했다.

 

// 틀린 코드
#include <fstream>
#include <algorithm>
using namespace std;

ifstream fin("card.inp");
ofstream fout("card.out");

int card[1000];
pair<int, int> dp[1000][1000];

int cal_sum(int n, int fb) {
	int s, e, sum;
	if (fb == 0) {
		s = 1;
		e = n - 1;
		sum = card[0];
	}
	else {
		s = 0;
		e = n - 2;
		sum = card[n - 1];
	}
	int time = 0;
	while (1) {
		int num = dp[s][e].first;
		int fb = dp[s][e].second;
		if (time == n - 1) break;
		if (time % 2 == 1) sum += num;
		time++;
		if (fb == 0) s++;
		else e--;
	}
	return sum;
}

int main() {
	int T, n;
	fin >> T;
	while (T--) {
		fin >> n;
		for (int i = 0; i < n; i++) {
			fin >> card[i];
			dp[i][i] = make_pair(card[i], 0);
		}
		for (int i = 0; i < n; i++) {
			for (int j = i + 1; j < n; j++) {
				if (card[i] == card[j]) {
					dp[i][j] = card[i + 1] < card[j - 1] ? make_pair(card[i], 0) : make_pair(card[j], 1);
					continue;
				}
				if (card[i] > card[j]) {
					dp[i][j] = make_pair(card[i], 0);
				}
				else {
					dp[i][j] = make_pair(card[j], 1);
				}
			}
		}

		int front = cal_sum(n, 0);
		int back = cal_sum(n, 1);

		fout << max(front, back) << "\n";
	}
}

 

그래서 재귀적으로 작은 쪽부터 돌면서 계산 결과가 가장 크게 나오는 것을 찾도록 했다.

 

#include <fstream>
#include <algorithm>
using namespace std;

ifstream fin("card.inp");
ofstream fout("card.out");

int card[1001];
int dp[1001][1001];

int cal_sum(int start, int end, bool turn) {
	if (start > end) return 0; // 확인 범위 초과시 종료
	if (dp[start][end]) return dp[start][end]; // 중복계산 막기 위해 설정
	
	int choice_front = cal_sum(start + 1, end, !turn);
	int choice_back = cal_sum(start, end - 1, !turn);

	if (turn) { // Alice 턴일 경우
		choice_front += card[start]; // 맨 앞 선택
		choice_back += card[end]; // 맨 뒤 선택
		return dp[start][end] = max(choice_front, choice_back); // 계산 결과 큰 것 선택
	} 
	else { // Computer 턴의 경우
    	// DP 배열은 Alice 경우만 생각하기 때문에 따로 선택된 카드 값을 더해주지 않음
        // 하지만 나중에 계산할 때 필요하기 때문에 DP에 저장해둠
        // Computer가 가장 작은 값을 선택하도록 만들었다고 생각하기
		return dp[start][end] = min(choice_front, choice_back); 
	}

}

void clear(int n) { // dp배열 초기화
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			dp[i][j] = 0;
		}
	}
}

int main() {
	int T, n;
	fin >> T;
	while (T--) {
		fin >> n;
		for (int i = 0; i < n; i++) {
			fin >> card[i];
		}
		fout << cal_sum(0, n - 1, true) << "\n";
		clear(n);
	}
}

 

표면상으로만 확인하지 말고 계속해서 확인해야하는 부분이라면 재귀적으로 확인하도록..!

 

 

dp는 너무너무 어렵다.. 아직도 이해가 잘 안간다..

어떻게 푼거지ㅋㅋ

'Algorithm > 🏫assignment' 카테고리의 다른 글

# MST  (0) 2022.11.09
# Adding Ways  (0) 2022.10.31
# 카드 선택  (0) 2022.10.08
# 정육면체  (0) 2022.10.07
# Coin Game  (0) 2022.10.01

댓글