题目大意:有n张钞票,面值可能不同。你要买一件东西,可能需要找零钱。问最少付多少钱,并求出最少的钞票张数。
题目分析:定义状态dp(i,w)表示前i张钞票凑成w元需要的最少钞票张数。则状态转移方程为dp(i,w)=min(dp(i-1,w),dp(i-1,w-a(i))+1)。其中a(i)为第i张钞票的面值。
代码如下:
//# define AC # ifndef AC # include<iostream> # include<cstdio> # include<cstring> # include<vector> # include<queue> # include<list> # include<cmath> # include<set> # include<map> # include<string> # include<cstdlib> # include<algorithm> using namespace std; # define mid (l+(r-l)/2) typedef long long LL; typedef unsigned long long ULL; const int N=10000; const int mod=1e9+7; const int INF=0x3fffffff; const LL oo=0x7fffffffffffffff; int n,w,a[105]; int dp[105][N*2+5]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; scanf("%d",&T); while(T--) { scanf("%d%d",&w,&n); int m=0; for(int i=0;i<n;++i){ scanf("%d",a+i); m+=a[i]; } m=min(m,N<<1); fill(dp[0],dp[0]+m+1,INF); dp[0][0]=0; dp[0][a[0]]=1; for(int i=1;i<n;++i){ dp[i][0]=0; for(int j=1;j<=m;++j){ if(j<a[i]) dp[i][j]=dp[i-1][j]; else{ dp[i][j]=INF; if(dp[i-1][j]!=-INF) dp[i][j]=dp[i-1][j]; if(dp[i-1][j-a[i]]!=INF) dp[i][j]=min(dp[i][j],dp[i-1][j-a[i]]+1); } } } while(dp[n-1][w]==INF||!dp[n-1][w]) ++w; printf("%d %d\n",w,dp[n-1][w]); } return 0; } # endif
时间: 2024-10-16 00:47:35