1、题意
N个数,看看有没有能够组成M的,有的话输出该序列,有多个解,输出最小的序列
2、思路
2.1 一开始看到题目,不会做,想成了递归,把M逐渐根据a[i] 进行划分,再二分另一个数,受不了太蠢了
2.2 看题解发现是背包问题:标准的01背包,价值===体积,但是要记录一下选过哪些。
第一种思路,先看看能不能装满,不能就No Solution,能的话,再从小到达,看看不同阶段的体积是不是有选,前一个状态如果存在的话,就输出该价值的硬币,先总再分
第二种思路,在选的时候就记录选了什么硬币,到最后处理到M的时候,直接就能返回,一步到位
3、代码
3.1 代码一
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 10010,M = 110;
int n,m;
int a[N];
bool f[N][M];
int main()
{
cin>>n>>m;
for(int i = 1;i<=n;i++) cin>>a[i];
sort(a + 1,a + n + 1,greater<int>());// 从大到小排序
f[0][0] = true;
for(int i = 1;i<=n;i++)// 标准01背包
for(int j = 0;j<=m;j++)
{
f[i][j] = f[i-1][j];
if(j>=a[i]) f[i][j] += f[i-1][j-a[i]];
}
if(!f[n][m]) puts("No solution");
else
{
bool is_first = true;
while(n)
{//因为a是从大到小,要从后面开始
if(m>=a[n]&&f[n-1][m-a[n]])// 逐渐向前看前面状态是不是装了硬币
{
if(is_first) is_first = false;
else cout<<" ";
cout << a[n];
m -= a[n];
}
n--;
}
}
return 0;
}
3.2 代码二
#include<bits/stdc++.h>
using namespace std;
int a[10100],b[110];
vector<int> dp[110];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0;i<n;i++)scanf("%d",&a[i]);
sort(a,a+n);
dp[0].push_back(0);
for(int i = n-1;i>=0;i--)
for(int j = m;j>=a[i];j--)
if(dp[j-a[i]].size()!=0)
{
dp[j] = dp[j-a[i]];
dp[j].push_back(a[i]);
}
if(dp[m].size()==0)printf("No Solution\n");
else
{
for(int i = dp[m].size()-1;i>=1;i--)printf("%d ",dp[m][i]);
}
return 0;
}