练习75

/************************************************************************************* 

  75. (钱币系统问题) 某钱币系统由 k (k≤20) 种硬币组成, 币值依次为 a[1], 
 a[2],...,a[k], 其中 a[i] (i=1,2,...,k) 为互不相同的正整数, 且依降序排列, 
 a[1]≤200. 给定某整数币值 n(n≤3000), 要求用最少枚数的硬币表示这个币值. 
    输入: 用文件输入已知数据, 格式为: 
      第 1 行: k (硬币种数) 
      第 2 行: a[1] a[2] ... a[k] (各币值用空格隔开,已按降序排列好) 
      第 3 行: n (给定的币值) 
    输出: 直接在屏幕上输出结果. 如果该钱币系统无法表示币值 n,应输出'No', 
 否则按以下格式输出: 
      第 1 行: 最少钱币枚数 r. 
      第 2 行: 输出若干形如 m*n 的表达式, m 为币值, n为使用该币值的枚数. 
 各式第 2 个因子之和应等于 r, 各式乘积之和应等于 n. 
    例: 设 (a[1],a[2],a[3])=(5,2,1),  n=12,  则应输出 
       3 
       5*2  2*1. 

  分析:求最优化组合问题可以用动态规划算法 
  用贪心算法,可以得到比较小的结果,但是不一定最小. 



  ***********************************************************************************/ 

#include <stdio.h> 
#include <malloc.h> 

void main() 
{ 
    int i,j; 
    int s,n; 
    int *val,**ts,**vs,*vx; 
    FILE *fp; 

    fp = fopen("input.txt","r"); 

    fscanf(fp, "%d", &n); 
    printf("硬币种类总数: %d",n); 
     
    val = (int*) malloc(n*sizeof(int)); 
    vx = (int*) malloc(n*sizeof(int)); 
    printf("%d种硬币的币值:/n",n); 
    for(i=0; i<n; i++) 
    { 
        fscanf(fp,"%d",&val[i]); 
        printf("%d ",val[i]); 
    } 
    fscanf(fp,"%d",&s); 
    printf("兑换金额: %d",s); 
    fclose(fp); 

    ts = (int**)malloc(n*sizeof(int*)); 
    vs = (int**)malloc(n*sizeof(int*)); 
    for(i=0; i<n; i++) 
    { 
        ts[i] = (int*)malloc((s+1)*sizeof(int)); 
        vs[i] = (int*)malloc((s+1)*sizeof(int)); 
    } 

    for(i=0; i<n; i++) 
    { 
        for(j=0; j<=s; j++) 
        { 
            if(i==0 && j>0) 
            { 
                ts[i][j] = j; 
                vs[i][j] = j; 
            } 
            else if(j == 0) 
            { 
                ts[i][j] = 0; 
                vs[i][j] = 0; 
            } 
            else if((j < val[i]) && (j > 0) && (i > 0)) 
            { 
                ts[i][j] = ts[i-1][j]; 
                vs[i][j] = 0; 
            } 
            else if((j >= val[i]) && (j > 0) && (i > 0)) 
            { 
                int temp,k; 

                ts[i][j] = ts[i-1][j]; 
                vs[i][j] = 0; 
                temp=j / val[i]; 
                for(k=1; k<=temp; k++) 
                { 
                    if(ts[i-1][j-k*val[i]]+k < ts[i][j]) 
                    { 
                        ts[i][j] = ts[i-1][j-k*val[i]] + k; 
                        vs[i][j] = k; 
                    } 
                } 
            } 
        } 
    } 

    { 
        int q = s; 
        vx[n-1] = vs[n-1][q]; 
        for(i=n-2; i>=0; i--) 
        { 
            int temp; 
            temp = q-vx[i+1] * val[i+1]; 
            vx[i] = vs[i][temp]; 
            q = temp; 
        } 
    } 

    fp = fopen("output.txt","w"); 
    printf("所需钱币总数: %d /n",ts[n-1][s]); 
    fprintf(fp,"%d/n",ts[n-1][s]); 
    for(i=0; i<n; i++) 
    { 
        printf("%d ",vx[i]); 
        if(vx[i]) 
        { 
            fprintf(fp, "%d*%d ", val[i], vx[i]); 
        } 
    } 
    printf("/n"); 
    fprintf(fp,"/n"); 

    fclose(fp); 
    free(val); 
    for(i=0; i<n; i++) 
    free(ts[i]); 
    free(ts); 
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值