题意:
题解:
以前好像做到过类似的题目,当然那个时候是
n
2
m
n^2m
n2m的时间复杂度过的,这个题目的话要优化
首先可以确认的是01背包,那么怎么记录路径?用pre表示当前是从哪里转移过来的
那么如何让字典序最小?先用大的货币,然后再做小的货币,这样子pre就可以贪心地取最后到达的地方,因为字典序来说,越前面越小越优
那么pre[i][j]表示第i个硬币必取,当前有j块钱的时候,是从哪里转移过来的
那么很明显pre[i][j]不一定是从pre[i-1][j]转移过来的,那么如果每次都去找的话,时间复杂度就会变成
n
m
n^m
nm,那么我们需要考虑优化,然后我们又知道,它因为字典序要最小,所以越后面的硬币一定是越优的,那么我们用mi[i]表示到现在为止,用i块钱的最优转移是mi[i]行(也就是必取第i个硬币)
那么就可以直接从mi转移到当前位置
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=205;
int a[N],mi[N];
struct node{
int i,j;
};
node pre[N][M];
bool cmp(int x,int y){return x>y;}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
m++;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n,cmp);
memset(mi,-1,sizeof(mi));
mi[1]=0;
pre[0][1]={-1,-1};
for(int i=1;i<=n;i++){
for(int j=m+1;j>a[i];j--){
if(~mi[j-a[i]]){
pre[i][j]={mi[j-a[i]],j-a[i]};
mi[j]=i;
}
}
}
if(mi[m]==-1)return 0*printf("No Solution\n");
int fi=mi[m],se=m;
while(se!=1){
printf("%d%c",se-pre[fi][se].j,pre[fi][se].j==1?'\n':' ');
int nfi=pre[fi][se].i;
se=pre[fi][se].j;
fi=nfi;
}
return 0;
}