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;
}

猜你喜欢

转载自blog.csdn.net/sincerit/article/details/83212057