【DFS+剪枝+特判】 OR 【变种背包DP】

题目详情 - L3-001 凑零钱 (30 分) (pintia.cn)

 思路一(DFS):用时6ms

暴力搜索+剪枝,但要注意特判一个特殊情况
就是当所有物品的总和加起来也凑不出答案的时候
这时候会递归所有点,时间消耗最大,可能会超时
以后遇到这种一定不存在答案还要遍历所有点的情况都注意一下

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 100010;

int w[N], n, m, sum;
vector<int> res;
bool has_answer, st[N];

void dfs(int u)
{
    if(u == m && !has_answer)
    {
        for(int i = 0; i < res.size(); i ++ )
        {
            cout << res[i];
            if(i != res.size() - 1) cout << " ";
            has_answer = true;
        }
        return ;
    }
    if(has_answer) return ;
    if(u > m)   return ;
    
    for(int i = 1; i <= n; i ++ )
    {
        if(!st[i])
        {
            st[i] = true;
            res.push_back(w[i]);
            
            dfs(u + w[i]);
            
            st[i] = false;
            res.pop_back();
        }
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ )   cin >> w[i];
    
    sort(w + 1, w + n + 1);
    
    for(int i = 1; i <= n; i ++ )   sum += w[i];
    if(sum < m) //Special check!
    {
        puts("No Solution");
        return 0;
    }
    
    dfs(0);
    if(!has_answer) puts("No Solution");
    
    return 0;
}


思路二(DP): 用时18ms

verctor保存路径

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 10010;

int n, m;
int f[N], v[N];
vector<int> res[N];

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ )   cin >> v[i];
    sort(v + 1, v + n + 1);
    
    for(int i = 1; i <= n; i ++ )
    {
        for(int j = m; j >= v[i]; j -- )
        {
            if(f[j] < f[j - v[i]] + v[i])
            {
                res[j] = res[j - v[i]];
                res[j].push_back(v[i]);
                f[j] = f[j - v[i]] + v[i];
            }
            else if(f[j] == f[j - v[i]] + v[i])
            {
                vector<int> t = res[j - v[i]];
                t.push_back(v[i]);
                if(t < res[j]) res[j] = t;
            }
        }
    }
    
    
    if(f[m] == m)
    {
        for(int i = 0; i < res[m].size(); i ++ )
        {
            cout << res[m][i];
            if(i != res[m].size() - 1)  cout << " ";
        }
    }
    else puts("No Solution");
    
    return 0;
}


思路三(DP):用时30s

回溯查找路径

#include <bits/stdc++.h>
using namespace std;
int dp[10010];
int w[10010];
bool choice[10010][10010];
bool cmp(int a,int b){return a > b;}
int main() {
	int n,m;
	cin>>n>>m;
	for(int i = 1;i <= n;i++){
		cin>>w[i];
	}
	sort(w + 1,w + n + 1,cmp);
	for(int i = 1;i <= n;i++){
		for(int j = m;j >= w[i];j--){
			if(dp[j] <= dp[j - w[i]] + w[i]){
				choice[i][j] = true;
				dp[j] = dp[j - w[i]] + w[i];
			}
		}
	}
	vector<int> res;
	if(dp[m] != m) cout<<"No Solution"<<endl;
	else{
		int v = m, index = n;
        while(v > 0) {
            if(choice[index][v] == true) {
                res.push_back(w[index]);
                v -= w[index];
            }
            index--;
        }
        for(int i = 0;i < res.size();i++) {
            if(i != 0) cout<<" ";
            cout<<res[i];
        }
	}
    return 0;
}

posted @ 2022-05-05 08:41  光風霽月  阅读(17)  评论(0编辑  收藏  举报