凑零钱 (30 分)
韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有 10(4)(下同没改哈哈哈)枚来自各个星球的硬币,需要请你帮她盘算一下,是否可能精确凑出要付的款额。
题目其他格式太不对CSDN的编辑器了,其他读者自己找一下,或许你们已经不用看了hh
注:我们说序列{ A[1],A[2],⋯ }比{ B[1],B[2],⋯ }“小”,是指存在 k≥1 使得 A[i]=B[i] 对所有 i<k 成立,并且 A[k]<B[k]。
输入样例 1:
8 9
5 9 8 7 2 3 4 1
输出样例 1:
1 3 5
输入样例 2:
4 8
7 2 4 3
输出样例 2:
No Solution
然后呢,这道题目肯定是动态规划这个重要的方法论的知识了,动态规划确实是需要静下心来慢慢琢磨的一个方面。因为要节省时间,就要使用更多的空间,这是我在这道题目中体会到的。
然后这道题目源码给出(不是dl勿喷hh )
然后这道题目就是体现出了动态规划的最重要的流程,第一步要想好怎么建立状态转移方程,子问题怎么才是重叠可以有相互关系的。
这道题目我的 最后思想是:从–给出的序列中的最小值–到--要凑足的总钱款之间建立规划,从小到大依次计算凑够每个值需要的序列,后一个的序列由前面计算过的序列产生。
这样一个动态规划的总计划。当然在实行过程中,要注意一些诸如插入排序之类的东西。
注意输出不要多余空格。
//动态规划--7-13 凑零钱问题
//从--给出的序列中的最小值--到--要凑足的总钱款之间建立规划,从小到大依次计算凑够每个值需要的序列,后一个的序列由前面计算过的序列产生
#include <iostream>
#include<algorithm>
#include<vector>
#include<string.h>
#include<string>
using namespace std;
int n, m;
int price[10010];//记录依次输入的序列值,然后在序列中重新排序
vector<int> have;//存入给定序列的序列值,(记录下每个值的个数),自始至终不变
vector<int> list[10010];//记录凑够每个值所需要的最小序列,用于从小到大算的状态转移过程
vector<int> cal[10010];//记录产生每个值对应的最小序列后,当前序列的剩余序列值
vector<int> temp;//暂存可能交换的序列,用于比较
int start;//动态规划的开始值,是给出的序列的最小值
//比较,产生较小的序列
bool cmp(vector<int> a, vector<int> b)
{
int lena = a.size(); int lenb = b.size();
int lenc = lena < lenb ? lena : lenb;
for (int i = 0; i < lenc; i++)
{
if (a[i] < b[i])
{
return true;
}
else if (a[i] > b[i])
{
return false;
}
else
{
continue;
}
}
return false;
}
//动态规划
void toDo()
{
//给第一个结点赋初值
start = price[0];
list[0].push_back(start);
cal[0][start]--;
for (int i = start +1; i <= m; i++)
{
cal[i - start] = have; int done = 0;
for (int j = i-1; j >=start; j--)
{
if (cal[j-start][i - j] > 0&& list[j - start].size()!=0)
{
if (!done)
{
cal[i - start] = cal[j - start];
cal[i - start][i - j]--;
list[i - start] = list[j - start];
vector<int>::iterator it = lower_bound(list[i - start].begin(), list[i - start].end(), i - j);
list[i - start].insert(it,i-j);
done = 1;
}
else
{
//比较得出较小的序列
temp = list[j - start];
vector<int>::iterator it = lower_bound(temp.begin(), temp.end(), i - j);
temp.insert(it, i - j);
if (cmp(temp, list[i - start]) == true)
{
list[i - start] = temp;
cal[i - start] = cal[j - start];
cal[i - start][i - j]--;
}
}
}
}
if (!done)
{
//没有找到符合要求的则要进行操作,给其赋一个合适的序列
list[i - start].clear();
if (have[i])
{
list[i - start].push_back(i);
cal[i - start][i]--;
}
}
else
{
continue;
}
}
}
int main()
{
cin >> n >> m; cal[0].resize(10010);
have.resize(10010);
for (int i = 0; i < n; i++)
{
cin >> price[i];
cal[0][price[i]]++;
have[price[i]]++;
}
sort(price, price + n);
toDo();
//输出
if (list[m - start].size() == 0)
{
cout << "No Solution";
}
else
{
//末尾不出现空格
for (int i = 0; i < list[m - start].size()-1; i++)
{
cout << list[m - start][i] << " ";
}
cout << list[m - start][list[m - start].size() - 1];
}
return 0;
}