poj1742-coins

来源:互联网 发布:什么电话卡最划算知乎 编辑:程序博客网 时间:2024/06/05 12:40

n种硬币每种amount个,求能凑出的<=m的钱价值种类数
一种一种地添加硬币种类数,对于每个价值,记录凑出这个价值时还剩多少个当前种类硬币到reach[j]
(j即价值)
对于第i种硬币,价值为j的情况
如果之前这个价值已经被凑出来过,那么完全没必要浪费当前种类硬币
reach[j]=coins[i].amount;
要不然看看reach[j-coins[i].price]处还有没有剩下硬币即reach[j-coins[i].price]>=0
有的话reach[j]=reach[j-coins[i].price]-1;
没有reach[j]=-1;
最后数一下有多少种情况被凑出来了。

#include <stdio.h>#include <iostream>#include <queue>#include <string.h>using namespace std;struct coin{    int price;    int amount;};bool operator<(const coin& a,const coin &b){    return a.price>b.price;}coin coins[110];int reach[100100]={0};int coinTypes=0;priority_queue<coin> middle;int n,m;int main(){    freopen("/home/myhyh/in","r",stdin);    while(scanf("%d%d",&n,&m)&&n&&m)    {        coinTypes=0;        int count=0;        memset(reach,-1,sizeof(reach));        reach[0]=0;        for(int i=0;i<n;i++)            scanf("%d",&coins[i].price);        for(int i=0;i<n;i++)            scanf("%d",&coins[i].amount);        //合并硬币种类。完全没必要,可以无视        for(int i=0;i<n;i++)            middle.push(coins[i]);        coins[0]=middle.top();        middle.pop();        for(int i=0;i<n-1;i++)        {            if(middle.top().price==coins[coinTypes].price)                coins[coinTypes].amount+=middle.top().amount;            else                coins[++coinTypes]=middle.top();            middle.pop();        }        //合并硬币种类。完全没必要,可以无视        for(int i=0;i<=coinTypes;i++)        {            for(int j=0;j<=m;j++)            {                if(reach[j]>=0)                    reach[j]=coins[i].amount;                else if(j<coins[i].price||reach[j-coins[i].price]<=0)                    reach[j]=-1;                else if(reach[j-coins[i].price]>0)                    reach[j]=reach[j-coins[i].price]-1;            }        }        for(int i=1;i<=m;i++)            if(reach[i]>=0)                count++;        printf("%d\n",count);    }}