A ergodic algorithm for the change problem - "clock model"

        Problem introduction: there is a problem of change in supermarkets or stores. For example, if you have four pieces of 10 yuan, two pieces of 20 yuan and one piece of 50 yuan, you need change 90. Of course, you can add two pieces of 20 to one piece of 50, or you can add four pieces of 10 to one piece of 50. The former consumes 3 pieces and the latter consumes 5 pieces. In this article, we want to solve the problem of how to calculate the minimum change.

        Of course, the initial idea is to start from the largest one. Take the above example. Pick one out of 50, there are 40 left, and then pick two out of 20, which is exactly equal to 90. The approximate algorithm is as follows   The array a[n] represents the denomination, b[n] represents the number of corresponding sheets, n represents the number of denomination types, and N represents the number of zeros.

i=b[n-1]
while(i>=1){
//Cycle from large face value
        if(N>=(a[n-1]*i)) {
            c[n-1]=a[n-1]; //Save face value
            d[n-1]=i;      //Number of saved sheets
            N=N-a[n-1]*i;
            n--;           //Prepare for the next cycle
            i=b[n-1]+1;    //Reduce the face value
            if(N==0) {
                i=0;       //Get the result and stop the cycle
            }
        }
        //If an item is inconsistent, proceed to the next cycle
        m=(N<a[n-1]*i);
        if(m==1&&i==1) {
            n--;
            i=b[n-1]+1;
            for(i=0; i<=n-1; i++) {
                c[i]=0;
                d[i]=0;
            }
        }
        i--;
    }
}

        Of course, we can easily find that this algorithm has great disadvantages. Suppose you have ten pieces of 1, ten pieces of 30, ten pieces of 50 and change 90, you will find that the above algorithm will get a non optimal solution of one piece of 50 plus one piece of 30 plus ten pieces of 1, because we can easily find that three pieces of 30 obviously consume the least number of pieces. So I decided to change the algorithm from finding the local optimal solution to the global optimal solution.

         To find the global optimal solution, it is inevitable to traverse all cases, but how to traverse? Use the method of finding all situations when calculating probability in high school. For example, we can do this for the above problems

1*10+30*10+50*101*10+30*9+50*10......1*0+30*0+50*10
1*10+30*10+50*91*10+30*9+50*9......1*0+30*0+50*9
......................................................................................
1*10+30*10+50*01*10+30*9+50*0......1*0+30*0+50*0

        That is, first fix all the previous ones, and then start to cycle the number of sheets of the last denomination until it reaches zero, and then start the cycle again next time. Moreover, the number of sheets of the previous denomination is reduced by one, that is, when the number of sheets of the latter denomination is reduced to zero, the number of sheets of the former denomination is reduced by one, forming a "recursive relationship". The code I wrote is as follows.

while(1){
    	if(b[0]==-1) break;
        b[5]--;
        for(j=5;j>=1;j--){
            if(b[j]==-1){
                b[j-1]--;
                b[j]=m[j];
            }
        }
    }

        In order to avoid too much calculation, I limit the denomination of banknotes to 6  , Array b [] has the same meaning as above. Array m [] stores the initial value of array b []. You may wonder why the conditional judgment is b[]==-1 instead of = = 1. After carefully sorting out this logic, you will find that if it is set to = = 1, the above situation (1 * 10 + 30 * 10 + 50 * 0) will not occur, but will become (1 * 10 + 30 * 9 + 50 * 0), so it is set to - 1. As for why I call it "clock model", you can try running the following code

​
#include<stdio.h>

int main()
{
	int i,j,m[6]; 
	int a[6]={1,5,10,20,50,100};
	int b[6]={10,10,10,10,10,10};
	for(i=0;i<6;i++){
        m[i]=b[i];
    }
    while(1){
    	if(b[0]==-1) break;
        b[5]--;
        for(j=5;j>=1;j--){
            if(b[j]==-1){
                b[j-1]--;
                b[j]=m[j];
            }
        }
        for(i=0;i<6;i++){
        	printf("%d*%d ",a[i],b[i]);
		}
		printf("\n");
	}
	
	return 0;
}

​

        Finally, the whole code and my running results are given

#include<stdio.h> 

int main()
{
    int N,i,j,sum1=0,sum2=0,min=10000;
    scanf("%d",&N);
    int a[6],b[6],m[6],r[6];
    for(i=0;i<6;i++){
        scanf("%d*%d;",&a[i],&b[i]);
    }
    for(i=0;i<6;i++){
        m[i]=b[i];
    }
    while(1){
    	if(b[0]==-1) break;
        b[5]--;
        for(j=5;j>=1;j--){
            if(b[j]==-1){
                b[j-1]--;
                b[j]=m[j];
            }
        }
        for(i=0;i<6;i++){
        	sum1+=(a[i]*b[i]);//Total amount 
        	sum2+=b[i];//Number of sheets 
		}
		//Find the minimum number of sheets 
		if(sum1==N&&sum2<min){
			min=sum2;
			for(i=0;i<6;i++){
				r[i]=b[i];
			}
		}
		sum1=0;sum2=0;
    }
    printf("%d\n",min);
    for(i=0;i<6;i++){
    	if(r[i]>0) printf("%d*%d\n",a[i],r[i]);
	}
    
    return 0;
}

          The above is all about a traversal algorithm I share. I hope it will help you.

Tags: Algorithm

Posted on Wed, 24 Nov 2021 20:14:45 -0500 by diondev