L3-001 凑零钱 (30 分)
题目
思路
01背包+路径还原,将01背包的这一段进行修改:
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= v[i]; j--)
{
dp[j] = max(dp[j - v[i]] + v[i], dp[j]);
}
}
//turn into
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= v[i]; j--)
{
if(dp[j] <= dp[j - v[i]] + v[i])
{
vis[i][j] = 1;
dp[j] = dp[j - v[i]] + v[i];
}
}
}
最后利用vis[i][j]
,从vis[index=n][val=m]
开始还原,若为0吗,index -= 1
;若为1,val -= v[index]
,直到val
的值为0。
代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f
#define pb push_back
using namespace std;
typedef pair<int, int> P;
const int N = 1e4 + 10;
const int M = 1e2 + 10;
typedef long long ll;
int dp[N];
int v[N];
int vis[N][M];
int main()
{
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
cin >> v[i];
}
sort(v + 1, v + n + 1, greater<int>());
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= v[i]; j--)
{
if(dp[j] <= dp[j - v[i]] + v[i])
{
vis[i][j] = 1;
dp[j] = dp[j - v[i]] + v[i];
}
}
}
if(dp[m] != m)
{
cout << "No Solution\n";
return 0;
}
int val = m, index = n, flag = 0;
while(val > 0)
{
if(vis[index][val])
{
if(flag)
cout << ' ';
else
flag = 1;
cout << v[index];
val -= v[index];
}
index--;
}
cout << endl;
return 0;
}