算法練習(32):Delete and Earn


題意:給出一個數組,定義一個操作,從中取一個數可以獲取數字表示的分數,然後要把與這個數字差的絕對值爲1的數都從數組中刪掉(意味着你再也得不到他們表示的分數)

分析與思路:這是一道很明顯的動態規劃題目,當然按照這個題意還不容易想出狀態轉移方程,先從題意找出規律來簡化一下,要取某個數時,其他等於他的數在最後肯定都會取完,因此很容易想到把重複數字歸一化,然後得出每個數代表的價值(數字*個數)。然後排序,從小到大,只分析前面跟當前的制約關係。設dp[i]代表在遍歷了前i個數並作出選擇時對應的當前最大獲取分數。對於每個數只有兩種選擇,選或者不選。

所以狀態轉移方程:

set[i]==set[i-1]時,dp[i]=(dp[i-2]+value[i])>dp[i-1]?(dp[i-2]+value[i]):dp[i-1]

else dp[i]=dp[i-1]+value[i]

代碼:

class Solution {
public:
	int deleteAndEarn(vector<int>& nums) {
		if (nums.size() == 0) return 0;
		vector<int> dataSet;//數組的無重複數字版本
		vector<int> dataValue;//dataSet對應的每個數的總價值
		for (int i = 0; i < nums.size(); i++) {
			int j = 0;
			for (j = 0; j < dataSet.size(); j++) {
				if (dataSet[j] == nums[i]) {
					dataValue[j] += nums[i];
					break;
				}
			}
			if (j == dataSet.size()) {
				dataSet.push_back(nums[i]);
				dataValue.push_back(nums[i]);
			}
		}
		for (int i = 0; i < dataSet.size()-1; i++) {//排序
			for (int j = i + 1; j < dataSet.size(); j++) {
				if (dataSet[j] < dataSet[i]) {
					int temp = dataSet[j];
					dataSet[j] = dataSet[i];
					dataSet[i] = temp;
					temp = dataValue[i];
					dataValue[i] = dataValue[j];
					dataValue[j] = temp;
				}
			}
		}
		int* dp = new int[dataSet.size()];
		dp[0] = dataValue[0];
		if (dataSet.size() == 1) return dp[0];
		if (dataSet[0] == dataSet[1] - 1) dp[1] = dp[0] > dataValue[1] ? dp[0] : dataValue[1]; 
		else dp[1] = dp[0] + dataValue[1];
		if (dataSet.size() == 2) return dp[1];
		for (int i = 2; i < dataSet.size(); i++) {
			if (dataSet[i - 1] == dataSet[i] - 1) {
				int temp = dp[i - 2] + dataValue[i];
				dp[i] = temp > dp[i - 1] ? temp : dp[i - 1];
			}
			else {
				dp[i] = dp[i - 1] + dataValue[i];
			}
		}
		int result = dp[dataSet.size() - 1];
		delete[] dp;
		return result;
	}
};


發佈了80 篇原創文章 · 獲贊 72 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章