poj 3040 贪心

来源:互联网 发布:java商店管理系统 编辑:程序博客网 时间:2024/06/06 18:38

题意:有n种面额的硬币。且面值大的一定能被面值小的整除。现告诉你每种面值硬币的个数。和一个值c。每周支出的钱必须大于等于c。问钱最多能用多少周。

 

 

#include<stdio.h>
typedef struct        //定义一个结构v表示coin的面额,而n表示v面额纸币的钱数。
{
         int v;
         int n;
}Coin;
Coin coin[25];
int min(int a,int b)
{
          return a>b?b:a;
}
void qsort(int l,int r)           //快速排序 (数据最大才25个,可以用其他排序方法)按面额从小到大
{
         Coin temp;
         int i,j;
         if(l<r)
         {
               i=l;
               j=r;
               temp=coin[l];
         while(i<j)

         {
                 while(i<j&&coin[j].v>=temp.v)
                       j--;
                 if(i<j)
                coin[i++]=coin[j];
                while(i<j&&coin[i].v<temp.v)
                      i++;
                if(i<j)
                coin[j--]=coin[i];
        }

        coin[i]=temp;
        qsort(l,i-1);
        qsort(i+1,r);
 }
}
int main(void)
{
             int N,C,i,amount=0,use[30],sum,num,ma;
             scanf("%d%d",&N,&C);

             for(i=0;i<N;i++)
                 scanf("%d%d",&coin[i].v,&coin[i].n);
            qsort(0,N-1);
            for(i=N-1;i>=0;i--) //如果纸币面额大于C直接使用。
             {
                    if(coin[i].v>=C)
                    {
                           amount+=coin[i].n;
                           coin[i].n=0;
                    }
                    else
                      break;
             }
            sum=C;
            while(1)
            {
                     sum=C;
                  // for(i=0;i<N;i++)
                 //  printf("%d ",coin[i].n);
                     memset(use,0,sizeof(use));
                     for(i=N-1;i>=0;i--)   //从面额大的开始,尽可能使总数接近sum,但是绝对不能超过sum
                     {
                                 if(sum>0&&coin[i].n)
                                 {
                                                 num=min(sum/coin[i].v,coin[i].n);
                                                 sum-=num*coin[i].v;

                                                 use[i]=num;
                                 }
                     }
                    if(sum>0)      //从面额小的到大的,使面额达到总数,或者刚好超出。
                     {
                                 for(i=0;i<N;i++)
                                 {
                                        if(sum>0&&coin[i].n)
                                        {
                                             num=min(coin[i].n-use[i],(sum+coin[i].v-1)/coin[i].v);

                                             sum-=num*coin[i].v;
                                             use[i]+=num;
                                        }
                                 }
                      }
                      if(sum>0)break; //经过上述的方法,sum还没到0或者负数,说明已经没办法了,程序结束
                      ma=1e9;
                      for(i=0;i<N;i++)
                      {
                             if(use[i])
                             {
                                    ma=min(ma,coin[i].n/use[i]);  //这次的对每种钱币选择最多可以执行ma次
                             }
                     }
                     amount+=ma;  //这种情况直接当作执行了ma次
                     for(i=0;i<N;i++)
                     {
                          if(use[i])
                          {
                                coin[i].n-=ma*use[i];//使数量变成上述情况执行ma次之后剩余数量
                          }
                     }
 }
 printf("%d\n",amount);

}

0 0