Pensé un poco en el problema, y se me ocurrió el siguiente hack rápido, que parece funcionar.
Aquí está el trozo de código que debería hacer el trabajo en principio con enteros:
function [exch]=achange(p,coins)
s=size(coins);
c=zeros(1,s(2));
coins=sort(coins,'descend');
it=1:s(2);
isaninteger = @(x)isfinite(x) & x==floor(x);
if p<coins(end)
return
end
if isaninteger(p)==0
exch.coins=coins;
exch.c=inf(1,s(2));
exch.rest=inf;
return
elseif any(isaninteger(coins)==0)
exch.coins=coins;
exch.c=inf(1,s(2));
exch.rest=inf;
return
end
rest=0;
while p>0
trQ=mod(p,coins)==0;
idx=it(trQ);
li=length(idx);
if isempty(idx)
rst=1;
rest=rest+rst;
p=p-rst;
elseif li>0 && li<s(2)
ps=it(trQ)==0;
idx2=idx;
idx2(ps)=[];
for k=1:li
if p>0
p=p-coins(idx2(k));
c(idx2(k))=c(idx2(k))+1;
end
end
elseif li==s(2)
for k=1:li
if p>0
p=p-coins(idx(k));
c(idx(k))=c(idx(k))+1;
end
end
end
end
exch.coins=coins;
exch.c=c;
exch.rest=rest;
end
Al menos para el siguiente ejemplo funciona:
>> exch=achange(57,[10 25])
exch =
struct with fields:
coins: [25 10]
c: [1 2]
rest: 12
>> exch.coins*exch.c' + exch.rest
ans =
57
o para:
>> exch=achange(51,[10 25])
exch =
struct with fields:
coins: [25 10]
c: [1 2]
rest: 6
>> exch.coins*exch.c' + exch.rest
ans =
51
y finalmente mi ejemplo de los comentarios:
>> exch=achange(60,[1 2 5 10 20])
exch =
struct with fields:
coins: [20 10 5 2 1]
c: [1 1 3 4 7]
rest: 0
>> exch.coins*exch.c'
ans =
60
Si alguna entrada no es un número entero, obtenemos
>> exch=achange(57,[5 .10 25])
exch =
struct with fields:
coins: [25 5 0.1000]
c: [Inf Inf Inf]
rest: Inf
o similar
>> exch=achange(57.8,[5 10 25])
exch =
struct with fields:
coins: [25 10 5]
c: [Inf Inf Inf]
rest: Inf
ACTUALIZACIÓN 21.11.2020
Debido al hecho de que la asignación de las especies no es óptima por el código anterior, que se puede ver, por ejemplo, por el primer ejemplo, donde la cantidad residual todavía se puede asignar a algunas monedas, proporciono una pequeña enmienda que debe producir mejores resultados.
El importe residual del ejemplo mencionado es $12$ indicando que la estructura del problema no cambia, lo que nos permite resolver el problema recursivamente. Es decir, debemos sustituir las líneas de código después del bucle While por la siguiente construcción If para invocar una llamada recursiva siempre que sea necesario.
if any(rest>coins)
exch2=achange(rest,coins);
exch.coins=coins;
exch.c=c+exch2.c;
exch.rest=exch2.rest;
else
exch.coins=coins;
exch.c=c;
exch.rest=rest;
end
Entonces podemos reducir la cantidad residual del primer ejemplo de $12$ a $2$ como podemos ver a través de
>> exch=achange(57,[10 25])
exch =
struct with fields:
coins: [25 10]
c: [1 3]
rest: 2
0 votos
Vale, pues deberías saber que el stackexchange de economía es para preguntas de economía, no de Matlab.
0 votos
@user253751 no en realidad nuestro centro de ayuda dice explícitamente: "Preguntas sobre software: Las preguntas relacionadas con el software utilizado en economía y econometría, son on-topic aquí." Ver aquí . Así que esta pregunta es totalmente en el tema porque es la aplicación de matlab a alguna pregunta de economía. Matlab se utiliza mucho en la economía para la modelización numérica - No reconozco el tipo de problema de arriba, ya que no está conectado a nada de lo que me especializo, pero parece un problema de Economía
2 votos
Su función parece estar bien. Supongamos que el bien cuesta 60 céntimos, y que tienes el siguiente vector de monedas $(1,2,5,10,20)$ entonces la función devuelve $(4,3,2,2,1)$ diciéndole que necesita 4 monedas de un céntimo, 3 de dos céntimos, etc., que suman 60 céntimos, que es el precio del bien.
0 votos
@BrianRomanchuk eso es correcto, solo funciona con enteros. Pero esto es un refinamiento que debemos dejar al autor.
1 votos
El algoritmo no diagnostica la incapacidad de obtener la cantidad solicitada, y puede fallar la solución correcta. Digamos que tenemos p=50 y c=[25, 10]. Devolverá c=[1,2] para sumar 45, y no [2,0] que da 50.
0 votos
@HolgerI.Meinhardt He borrado mi comentario porque he leído mal el código.
0 votos
@BrianRomanchuk tienes razón, el código no puede manejar tu ejemplo, entra en un bucle infinito.
0 votos
Sí, me he dado cuenta de que no se rompe después de publicar eso. El bucle while podría romperse si no se encuentran cambios, y terminará con la cantidad menor que el objetivo.
0 votos
@HolgerI.Meinhardt ¡Muchas gracias! Ahora entiendo, por qué Matlab no me da una solución y tuve que dejar de depurar. Es un bucle infinito.
0 votos
@BrianRomanchuk ¿Pero cómo podría romper el bucle while y dejar que termine con la cantidad menor que el objetivo?
0 votos
@Hokkaido21 Para romper el bucle, hay que añadir una comprobación dentro del bucle de que se han realizado cambios. Por ejemplo, poner un booleano en falso antes del bucle for, luego si se encuentra una moneda, ponerlo en verdadero. Si el booleano sigue siendo falso después del for, se sale del while. Hace años que no trabajo con Matlab, así que no estoy seguro de la sintaxis. El punto clave es que siempre que tengas un bucle while, necesitas asegurarte de que tienes una condición de terminación que debe dispararse.
0 votos
@BrianRomanchuk ¡Bien, gracias! Eso tiene mucho sentido.