1. 程式人生 > >sincerit 演算法競賽寶典--油桶問題

sincerit 演算法競賽寶典--油桶問題

演算法競賽寶典–油桶問題
題目描述
楚繼光揚揚得意道:“當日華山論劍,先是他用黯然銷魂掌破了我的七十二路空明拳,然後我改打降龍十八掌,卻不防他伸開食指和中指,竟是六脈神劍,又勝我一籌。可見天下武學彼此剋制,武學之道玄之又玄!……哎,誰用炒鍋敲我頭?”

楚繼光的老媽大聲罵道:“玩個石頭剪刀布都說得這般威風,炒菜沒油了,快給我去裝!”

“這麼凶幹嘛?不就吹吹牛嘛。”楚繼光邊嘟嘟囔囔邊走進儲藏室,看到儲藏室有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;
}