使用贪婪方法确定进行找零所需的最小硬币数量

时间:2019-03-06 17:24:37

标签: c greedy

作为我的“算法设计和分析”课程的一项作业,我被要求使用贪婪的方法来确定进行更改所需的最小硬币数量。我想出了这种直观的方法:

#include<stdio.h>
#include<stdlib.h>

int main(){
  int hundreds=0,tens=0,ones=0,sum=0;

  printf("Enter a sum of money in range 1 to 999\n");
  scanf("%d",&sum);
  while(sum!=0) {
    if (sum<10&&sum>=1){
      ones=sum/1;
      sum-=ones;
    }
    else if(sum>=10&&sum<100){
      tens=sum/10;
      sum-=tens*10;
    }
    else if(sum>=100&&sum<=999){
      hundreds=sum/100;
      sum-=hundreds*100;
    }
    else{
      printf("Error");
      exit(0);
    }
  }

  printf("%d $100, %d $10, %d $1",hundreds,tens,ones);
  return 0;
}

这种方法贪婪吗? 如何证明程序正确并使用贪婪方法?

3 个答案:

答案 0 :(得分:4)

这确实是贪婪的方法,但是您需要颠倒if-then-else的顺序。通常,贪婪表示当前要消耗的最大数量。

您需要首先检查最大的硬币。不需要while循环。

if(sum>=100) {
  hundreds=sum/100;
  sum-=hundreds*100;
}
if(sum>=10){
  tens=sum/10;
  sum-=tens*10;
} 
ones = sum; 

答案 1 :(得分:1)

您的代码不够贪婪,因为它可能更糟:

#include<stdio.h>
#include<stdlib.h>

int main(){
  int hundreds=0,tens=0,ones=0,sum=0;

  printf("Enter a sum of money in range 1 to 999\n");
  if ((scanf("%d",&sum) == 1) && (sum >= 1) && (sum <= 999)) {
    while(sum!=0) {
      if (sum<10&&sum>=1){
        ones += 1;
        sum -= 1;
      }
      else if(sum>=10&&sum<100){
        tens += 1;
        sum -= 10;
      }
      else if(sum>=100&&sum<=999){
        hundreds += 1;
        sum -= 100;
      }
      else{ /* impossible case in fact */
        printf("Error");
        exit(0);
      }
    }

    printf("%d $100, %d $10, %d $1\n",hundreds,tens,ones);
  }
  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra g.c
pi@raspberrypi:/tmp $ ./a.out
Enter a sum of money in range 1 to 999
997
9 $100, 9 $10, 7 $1

  

我如何证明程序正确

一种证明代码正确的(贪婪)方法是使用残酷的力量检查从1到999的结果:

#include<stdio.h>
#include<stdlib.h>

int main(){
  int n;

  for (n = 1; n <= 999; ++n) {
    /* the algo */
    int hundreds=0,tens=0,ones=0, sum = n;

    while(sum!=0) {
      if (sum<10&&sum>=1){
        ones += 1;
        sum -= 1;
      }
      else if(sum>=10&&sum<100){
        tens += 1;
        sum -= 10;
      }
      else if(sum>=100&&sum<=999){
        hundreds += 1;
        sum -= 100;
      }
      else{ /* impossible case in fact */
        printf("Error");
        exit(0);
      }
    }

    /* check */
    if ((hundreds*100 + tens*10 + ones) != n) {
      printf("error for %d : %d $100, %d $10, %d $1\n",n, hundreds,tens,ones);
      exit(0);
    }
  }
  puts("all ok");
  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra g.c
pi@raspberrypi:/tmp $ ./a.out
all ok

答案 2 :(得分:0)

以下建议的代码:

  1. 干净地编译
  2. 不包括那些未使用的头文件
  3. 遵循公理:每行仅一个语句,每个语句(最多)一个变量声明。
  4. 执行所需的功能
  5. 执行适当的错误检查
  6. 执行“贪婪”算法,以最少数量的“账单”尽可能快地消耗掉“金钱”

现在,建议的代码:

#include <stdio.h>


int main( void )
{
    int sum;

    do
    {
        printf("Enter a sum of money in range 1 to 999\n");
        if( scanf("%d",&sum) != 1)
        {
            fprintf( stderr, "scanf failed\n");
            return -1;
        }       
    } while( sum<0 || sum>999 );

    int hundreds = sum/100;
    sum          = sum % 100;
    int tens     = sum/10;
    sum          = sum % 10;
    int ones     = sum;

    printf("%d $100, %d $10, %d $1\n",hundreds,tens,ones);
}

建议的代码将忽略50美元,20美元,5美元和2美元的美国账单。