找硬币题解
问题 A: 找硬币
时间限制: 1 Sec 内存限制: 64 MB题目描述
小蛇是金融部部长。最近她决定制造一系列新的货币。假设她要制造的货币的面值为x1,x2,x3… 那么x1必须为1,xb必须为xa的正整数倍(b>a)。例如 1,5,125,250就是一组合法的硬币序列,而1,5,100,125就不是。不知从哪一天开始,可爱的蛇爱上了一种萌物——兔纸!从此,小蛇便走上了遇上兔纸娃娃就买的不归路。某天,小蛇看到了N只可爱的兔纸,假设这N 只兔纸的价钱分别是a1,a2…aN。现在小蛇想知道,在哪一组合法的硬币序列下,买这N只兔纸所需要的硬币数最少。买兔纸时不能找零。
输入
第一行,一个整数N,表示兔纸的个数
第二行,N个用空格隔开的整数,分别为N只兔纸的价钱
输出
一行,一个整数,表示最少付的钱币数。
样例输入
2 25 102
样例输出
4
提示
样例解释:共有两只兔纸,价钱分别为25和102。现在小蛇构造1,25,100这样一组硬币序列,那么付第一只兔纸只需要一个面值为25的硬币,第二只兔纸需要一个面值为100的硬币和两个面值为1的硬币,总共两只兔纸需要付4个硬币。这也是所有方案中最少所需要付的硬币数。
1<=N<=50, 1<=ai<=100,000
这道题当时目测是一道数学+搜索或数学+DP题,然后默默地只打了28分。
这道题我用的是搜索A的,但正解是DP(我竟然都猜对了,不过貌似还没有搜索快),首先一个数一定可以被分解为若干个素数的积,我们可以利用这点只去枚举素数这样能方便不少。指针恒说这道题实际就是一个秦九昭,还真是。
我们可以得知a[i]=k[2]*x+a[i]%k[2],x为某一个常数,a[i]%b就是需要拿一块钱去补的硬币数。
然后我们又可知a[i]-a[i]%k[2]=k[2]*x=k[3]*xx+k[2]*x%k[3]……由此我们就可以利用这点去放心大胆的去DFS第j步的余数就是使用k[j-1]的张数。什么时候被排序后的最大的a[1]为0或1了找一下就好了,至于剪枝,传统做法。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #define N 1000005 9 using namespace std; 10 int n; 11 int a[55]; 12 int bj(int a,int b){ 13 return a>b; 14 } 15 bool fss[N]; 16 int zz; 17 int ss[N]; 18 void xs(){ 19 int mx=a[1]; 20 for(int i=2;i<=mx;i++) 21 { 22 if(!fss[i]) 23 { 24 zz++; 25 ss[zz]=i; 26 } 27 for(int j=1;j<=zz;j++) 28 { 29 if(ss[j]*i>mx)break; 30 fss[ss[j]*i]=1; 31 if(!(i%ss[j])) 32 break; 33 } 34 } 35 } 36 long long ans=0x7ffffff; 37 int b[52],c[52],b2[52]; 38 inline void dfs(int wz,long long sum){ 39 //cout<<b[wz]<<endl; 40 long long an=0; 41 int d[52]; 42 43 for(int i=1;i<=n;i++) 44 { 45 an+=(a[i]%b[wz]); 46 a[i]/=b[wz]; 47 } 48 if(sum+an>=ans)return; 49 memcpy(d,a,sizeof(a)); 50 if(a[1]!=1&&a[1]!=0) 51 { 52 for(int i=1;i<=zz;i++) 53 { 54 if(b2[wz]*ss[i]>c[1])break; 55 b[wz+1]=ss[i]; 56 b2[wz+1]=b2[wz]*ss[i]; 57 dfs(wz+1,an+sum); 58 b[wz+1]=0; 59 b2[wz+1]=0; 60 memcpy(a,d,sizeof(a)); 61 } 62 } 63 else 64 { 65 long long as=0; 66 for(int i=1;i<=n;i++) 67 { 68 if(a[i])as+=1; 69 } 70 int la=1; 71 for(int i=1;i<=wz;i++) 72 { 73 la*=b[i]; 74 } 75 ans=min(ans,sum+an+as); 76 } 77 } 78 int main(){ 79 // freopen("coin.in","r",stdin); 80 // freopen("coin.out","w",stdout); 81 scanf("%d",&n); 82 for(int i=1;i<=n;i++) 83 { 84 scanf("%d",&a[i]); 85 c[i]=a[i]; 86 } 87 sort(a+1,a+n+1,bj); 88 sort(c+1,c+n+1,bj); 89 xs(); 90 b[1]=1;b2[1]=1; 91 b[0]=1;b2[0]=1; 92 dfs(1,0); 93 printf("%lld ",ans); 94 //while(1); 95 return 0; 96 }