sincerit 演算法競賽寶典--油桶問題
阿新 • • 發佈:2018-11-05
演算法競賽寶典–油桶問題
題目描述
楚繼光揚揚得意道:“當日華山論劍,先是他用黯然銷魂掌破了我的七十二路空明拳,然後我改打降龍十八掌,卻不防他伸開食指和中指,竟是六脈神劍,又勝我一籌。可見天下武學彼此剋制,武學之道玄之又玄!……哎,誰用炒鍋敲我頭?”
楚繼光的老媽大聲罵道:“玩個石頭剪刀布都說得這般威風,炒菜沒油了,快給我去裝!”
“這麼凶幹嘛?不就吹吹牛嘛。”楚繼光邊嘟嘟囔囔邊走進儲藏室,看到儲藏室有N個油桶都裝滿了油,這N個油桶容積各不相同(容積為整數),楚繼光需要M升油(M也為整數),請你不借助任何其他容器,判斷能否直接在N桶油中取任意K桶(1≤K≤N)油,其油的總量正好是M升,如果可以,就輸出yes,否則輸出no。
輸入
第一行為兩個整數N,M,第二行為N個整數,即油桶的容積。
輸出
輸出結果即yes或者no。
樣例輸入
5 10
1 2 3 1 1
樣例輸出
no
遞迴搜尋法
遞迴出口
剪枝
遞迴搜尋策略部分
/*
油桶問題
*/
#include <iostream>
#include <algorithm>
using namespace std;
int n, M, oil[100];
// 這個遞迴搜尋遍歷了所有的組合可能一定能得出答案
int DFS(int sum, int k) { // sum表示已經取了多少油,再處理第k桶油
if (k > n) return 0;
if (sum >= M) {
if (sum == M) return 1;
return 0;
}
// 對於第k桶油有兩種情況, 取或不取
if (DFS(sum+oil[k], k+1) == 1) return 1;
if (DFS(sum, k+1) == 1) return 1;
return 0;
}
int main() {
cin >> n >> M;
for (int i = 1; i <= n; i++) cin >> oil[i];
if (DFS(0, 1)) cout << "yes\n";
else cout << "no\n";
return 0;
}
/*
01揹包解法
n桶油 每桶油的價值等於體積
問能不能儘可能的裝滿容量為M的揹包使之價值最大
現在的問題是能否恰好裝滿揹包
*/
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f
// dp[i][j]表示前i桶油揹包容量為j時的最大價值
// 邊界 dp[i][0] = 0
// 轉移方程 dp[i][j] = max(dp[i-1][j], dp[i-1][j-oil[k]] + oil[k]);
// 進行優化成一維陣列
int dp[100];
int oil[100];
int main() {
int n , M;
while (cin >> n >> M) {
for (int i = 1; i <= n; i++) cin >> oil[i];
memset(dp, -INF, sizeof(dp));
dp[0] = 0; // 表示恰好能裝滿 比如dp[j-oil[i]] 而j容量剛好等於oil[i]物體體積
// 遞迴的思想就相當於遞迴出口
for (int i = 1; i <= n; i++) {
for (int j = M; j >= oil[i]; j--) {
dp[j] = max(dp[j], dp[j-oil[i]]+oil[i]);
}
}
if (dp[M] == M) cout << "yes\n";
else cout << "no\n";
}
return 0;
}