Discription
I have some (say, n) marbles (small glass balls) and I am going to buy some boxes to store them. The
boxes are of two types:
T ype 1: each box costs c1 Taka and can hold exactly n1 marbles
T ype 2: each box costs c2 Taka and can hold exactly n2 marbles
I want each of the used boxes to be filled to its capacity and also to minimize the total cost of
buying them. Since I find it difficult for me to figure out how to distribute my marbles among the
boxes, I seek your help. I want your program to be efficient also.
Input
The input file may contain multiple test cases. Each test case begins with a line containing the integer
n (1 ≤ n ≤ 2, 000, 000, 000). The second line contains c1 and n1, and the third line contains c2 and n2.
Here, c1, c2, n1 and n2 are all positive integers having values smaller than 2,000,000,000.
A test case containing a zero for n in the first line terminates the input.
Output
For each test case in the input print a line containing the minimum cost solution (two nonnegative
integers m1 and m2, where mi = number of T ypei boxes required) if one exists, print ‘failed’ otherwise.
If a solution exists, you may assume that it is unique.
Sample Input
43
1 3
2 4
40
5 9
5 12
0
Sample Output
13 1
failed
题意
有n个弹球,现在要把这些弹球全部装进盒子里,第一种盒子每个盒子c1美元,可以恰好装n1个弹球;第二种盒子每个盒子c2元,可以恰好装n2个弹球。找出一种方法把这n个弹球装进盒子,每个盒子都装满,并且花费最少的钱。
思路
这道题,一看样例就很眼熟,其实和坐船过河(我贪心做的)是一道题,然后我拿坐船那道题的代码交过来发现过不了,超时了,然后我就重新看了下,发现这是道扩展的欧几里得题。
参考了题解的分析过程。
参考题解
假设第一种盒子买m1个,第二种盒子买m2个,则n1*m1 + n2*m2 = n
。
由扩展欧几里得ax+by=gcd(a,b)
,如果n%gcd(a,b)!=0
,则方程无解。特解为:
m2=0时,m1=nx/g;
m1=0时,m2=ny/g;
所以通解为:
m1=nx/g + bk/g;
m2=ny/g - ak/g,
因为m1和m2不能是负数,k的取值范围:-nx/b <= k <= ny/a
将通解带入,花费为:
Money=c1*(-xn/g+bk/g)+c2*(yn/g-ak/g) = ((bc1-ac2)/g)k+(c1xn+c2yn)/g;
所以:
当bc1-ac2 >= 0,k取最小值时花费最少;
bc1-a*c2 < 0,k取最大值时花费最少.
AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll x,y,n,c1,n1,c2,n2,ans1,ans2;
ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
ll r=ex_gcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-a/b*y;
return r;
}
int main()
{
while(scanf("%lld",&n)!=EOF)
{
if(n==0)
break;
scanf("%lld%lld%lld%lld",&c1,&n1,&c2,&n2);
ll tmp=ex_gcd(n1,n2,x,y);
ll down=ceil(1.0*-n*x/n2);
ll up=floor(1.0*n*y/n1);
if(down>up||n%tmp!=0)
{
printf("failed\n");
continue;
}
else
{
if (c1*n2<c2*n1)
{
x=n*x/tmp+n2/tmp*up;
y=n*y/tmp-n1/tmp*up;
}
else
{
x=n*x/tmp+n2/tmp*down;
y=n*y/tmp-n1/tmp*down;
}
printf("%lld %lld\n", x, y);
}
}
return 0;
}