UVA 10313 Pay the Price

题目大意:提供面额1~300的硬币(美元硬币这题性质一样),题目有三种输入,分别是:

                      1,输入N——输出1~300硬币组成N的方案数;

                      2,输入N,L1——输出组成N的方案数中,硬币数不超过L1的方案数;

                      3,输入N,L1,L2——输出组成N的方案数中, L1 <= 硬币数 <= L2的方案数;

解题策略:重要结论,组合N硬币数不超过L1的方案数 = 组合N硬币面额最大不超过L1的方案数;

                           上述结论可通过Ferrers图证明(这货是组合数学里的东西,小菜不懂啊。。);

                 所以通过该结论,这题就可以uva 674 Coin Change联系起来。

                 由于是dp基础题,所以就不献丑谈算法了,说下注意点和不同点吧:

                 1,解决输入问题,网上都是用sscanf()函数,由于不熟悉,就用字符流解决了;

                 2,在判断上下限时,必须考虑上限超过300这种坑爹数据(用min函数解决);

                 3,当价格为0而且下限为0时,只要一种组合方案;

                

                 算法的晦涩复杂和美妙无比都在一瞬之间啊,最后谢谢周B捷童鞋~

         

/*
   UVA 10313 Pay the Price
   AC by J.Dark
   ON 2013/3/15
   Time 0.404s
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <sstream>
#include <algorithm>
const int maxn = 310;
using namespace std;
unsigned long long int dp[maxn][maxn];
int N, L1, L2;
int price, minNum, maxNum; 
char temp[100];

void solve(){
     memset(dp, 0, sizeof(dp));
     dp[0][0]=1;
     for(int i=0; i<=300; i++)   {dp[0][i] = 1;}
     for(int j=1; j<=300; j++){
        for(int i=1; i<=300; i++){
               dp[i][j] = dp[i][j-1];
               if(i-j >= 0) {dp[i][j] += dp[i-j][j];}  
        }
     }
   
}


int main(){
    solve();
    
    while(gets(temp)!=NULL)
    {              
       int num, tc = 0;
       //定义字符流,分割数字 
       stringstream ss(temp);
       while(ss >> num && tc <=3)
       {
          tc++;
          if(tc == 1) price = num;
          if(tc == 2) L1 = num;
          if(tc == 3) L2 = num;
       }
       //根据数字情况判断硬币数上下限 
       if(tc == 1)  {maxNum = 300; minNum = 0;}
       if(tc == 2)  {maxNum = min(300, L1); minNum = 0;}
       if(tc == 3 ) {minNum = L1, maxNum = min(300, L2);}
       //特判
       if(price == 0 && minNum == 0)   {cout << 1 << endl;}
       else {cout << dp[price][maxNum]-dp[price][minNum-1]<< endl;}
    }
      
    //system("pause");
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值