1176_Two_Ends
题目链接:
题目大意:
很简单的一道题目,甲乙从卡片堆中轮流拿卡片,要使甲得到的卡片数字和最大,求这时甲乙数字和的差.两个人每次只能拿卡片队列中最左边或者最右边的一张,而乙每次已经设定好都会拿左右两张中比较大那张(相同的话拿左边的).说白就是求一个使甲能拿到最大数字和的策略
思路:
假设卡片序号为0到n - 1,(a,b)表示从序号a到b的卡片中甲能拿到的最大和,要求的(a,b),需要首先求出(a,b - 2),(a + 1, b - 1)和(a + 2, b),在这三种情况中甲乙各再取一张卡片,哪种使得甲的和最大的话结果就是哪个.一开始使用递归的方法超时了,因为整个过程中确实进行了很多重复的计算,所以增加了数组record[][]来记录产生的过程结果,避免重复计算,其实就是动态规划中带记录的自顶向下的方法.
代码:
#include <iostream> #include <memory.h> using namespace std; int record[1001][1001];//用来记录递归过程产生的结果,避免重复的计算节省时间 int get_best_points_recursive(int *cards, int left_index, int right_index); int main() { int n, count = 1; while (cin >> n && n != 0) { memset(record, 0, sizeof(record)); int cards[n], total_points = 0; for (int i = 0; i < n; ++i) { cin >> cards[i]; total_points += cards[i]; } int best_points = get_best_points_recursive(cards, 0, n - 1); cout << "In game " << count << ", the greedy strategy might lose by as many as " << best_points - (total_points - best_points) << " points." << endl; count++; } return 0; } int get_best_points_recursive(int *cards, int left_index, int right_index) { if (record[left_index][right_index] == 0) {//这个区间的结果没计算过需要计算并将结果存到record中 if (right_index - left_index == 1) { record[left_index][right_index] = max(cards[left_index], cards[right_index]); } else { int left_max, right_max; //先取左边一张的最大和和先取右边一张的最大和 if (cards[left_index + 1] >= cards[right_index]) { //对手在剩下的卡片中拿左边的那张 left_max = cards[left_index] + get_best_points_recursive(cards, left_index + 2, right_index); } else { left_max = cards[left_index] + get_best_points_recursive(cards, left_index + 1, right_index - 1); } if (cards[left_index] >= cards[right_index - 1]) right_max = cards[right_index] + get_best_points_recursive(cards, left_index + 1, right_index - 1); else right_max = cards[right_index] + get_best_points_recursive(cards, left_index, right_index - 2); record[left_index][right_index] = max(left_max, right_max); } } return record[left_index][right_index]; }