L3-001 凑零钱 (30 分)
韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有 104 枚来自各个星球的硬币,需要请你帮她盘算一下,是否可能精确凑出要付的款额。
解题思路:
将所有硬币用vector从小到大排序;(保证最小序列的可能)
用dfs对其进行遍历查找符合条件的第一个序列(最小序列)
#include<bits/stdc++.h>
using namespace std;
vector<int> v,temp;//存储所有硬币和存储符合条件的硬币
int flag=0,flag2=0;//标记找到符合序列和标记总金额超过规定金额
int n,m;
void DFS(int n,int sum)//n:第n个硬币 sum:目前总金额
{
if(sum==m) //说明已经找到了
{
flag=1;
return ;
}
if(sum>m)//用flag2标记,表示后面的就不用找了
{
flag2=1;
return ;
}
for(int i=n+1;i<v.size();i++)
{
temp.push_back(v[i]);//递归前将当前硬币金额录入
DFS(i,sum+v[i]);
if(flag) return;//找到
temp.pop_back();//如果不符合条件就回溯(有点难理解,后面有例题)
if(flag2)//后面的更大
{
flag2=0;//要置零,重复利用
break;//直接退出
}
}
}
int main(void)
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
int a;
cin>>a;
v.push_back(a);
}
//测试点6 所有钱都不够
int sum=0;
for(int i=0;i<v.size();i++)
{
sum+=v[i];
}
if(sum<m)
{
cout<<"No Solution";
return 0;
}
sort(v.begin(),v.end());//排序以后,第一个满足条件的序列一定是最小序列
for(int i=0;i<v.size();i++)
{
temp.push_back(v[i]);//先录入
DFS(i,v[i]);
//只要有符合条件的或者第一个硬币金额就大于总金额就退出(因为vector是从小到大排序的)
if(flag||flag2) break;
temp.pop_back();//不满足再回溯
}
int flag1=0;//按条件输出空格
if(flag)
{
for(int i=0;i<temp.size();i++)
{
if(flag1) cout<<" ";
cout<<temp[i];
flag1=1;
}
}
else cout<<"No Solution";
return 0;
}
关于dfs的回溯可以用这么一道题理解: