C.How_to_Fail_at_Programming_Contest


title: C.How_to_Fail_at_Programming_Contest
date: 2019-10-05 22:20:11
categories:

  • ACM
    tags:
  • 揹包
  • 基礎dp

最近比賽碰到了一道揹包問題,大意就是在揹包儘可能裝的多的情況下
獲取最小价值。給?整蒙⚪了。我就決定複習一下揹包問題。

首先,回顧一下01揹包和完全揹包的轉移方程

01揹包

狀態轉移方程: F[i][j] = max{ F[i-1][j], F[i-1][j- C[i]] + W[i] }

//倒着滾
void ZeroOnePack(F,C,W){
    for(v = V to C){
        F[v] = max(F[v],F[v-C] + W)
    }
}

就是拿和不拿

完全揹包

狀態轉移方程: F[i][j] = max{ F[i-1][j], F[i][j-C[i]] + W[i] }

//順着滾
void CompletePack(F,C,W){
    for(v = C to V){
        F[v] = max(F[v],F[v-C] + W)
    }
}

因爲可以拿多個所以直接在第i層滾動就可以了,不用去i-1層

所以01揹包用滾動數組的時候是 倒着滾,因爲要用前一層的。
而完全揹包用滾動數組的時候要 正着滾

多重揹包

就是物品有多個,但是有限。

def MultiplePack(F,C,W,M){ //M件物品
    if (C*M >= V){ //足夠多,可以視爲完全揹包
        CompletePack(F,C,W)
        return
    }
    k = 1       //二進制思想
    while(k < M){
        ZeroOnePack(kC,kW)
        M = M - k
        k = 2k
    }
}

害,簡單的複習了一下。
揹包九講還有好多沒有看完,還要再慢慢琢磨琢磨。

其實主要就是補一下昨天的C題。

題意上面說了。

解題思路: 維護 F[i][j] 的同時 再維護一個 left[i][j]
F[i][j] 表示前 i 個物品的時候的最小价值,left[i][j] 表示前 i 個物品的時候取最小价值的時候所剩餘的空間

轉移的時候,當left[i-1][j] >= C[i] 的時候,此時必須選第i道題目,如果不選,和題意違背
這點很重要!!

在轉移的時候分兩種情況
選和不選

F[i][j] = F[i-1][j - C[i]] + W[i];
left[i][j] = left[i-1][j - C[i]]; //選了後剩餘的空間不變,多出來的空間被選的物品佔滿了

不選

F[i][j] = F[i-1][j];
left[i][j] = F[i-1][j-1];

用滾動數組優化後

核心代碼

for (int v = V; v >= C[i]; v--) {
    if (L[v] >= C[i] || F[v - C[i]] + W[i] < F[v]) {
        F[v] = F[v - C[i]] + W[i];
        L[v] = L[v - C[i]];
    }
}

當然,處理前要按C[i]從小到大排序

完整代碼

話說這樣的排序就很懶。

#include<bits/stdc++.h>
using namespace std;

int C[3000], W[3000];
int r[3000];
int n, V;
int L[3000], F[3000];

bool cmp(int x, int y) {
	return(C[x] < C[y]);
}

int main() {
	cin >> n >> V;
	for (int i = 1; i <= n; i++) {
		cin >> C[i] >> W[i];
		r[i] = i;
	}
	sort(r + 1, r + 1 + n, cmp);

	for (int i = 0; i < 2050; i++) {
		F[i] = 0;
		L[i] = i;
	}
	for (int k = 1; k <= n; k++) {
		int i = r[k];
		for (int v = V; v >= C[i]; v--) {
			if (L[v] >= C[i] || F[v - C[i]] + W[i] < F[v]) {
				F[v] = F[v - C[i]] + W[i];
				L[v] = L[v - C[i]];
			}
		}
	}
	cout << F[V] << endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章