PC/UVa 110707/10090

c1美元的盒子可以装n1个弹珠,c2美元的盒子可以装n2 个弹珠,一共n个弹珠问怎样花最少的钱将盒子装满弹珠,且不留弹珠

一看没思路,再看,可能是跟线性同余方程有关,

欧几里得扩展算法

a*x+b*y=gcd(a,b)

b*x1+(a-floor(a/b)*b)y1=gcd(a,b);

将算式扩展开可得

x=y1;

y=x1-floor(a/b)*y1;

求出 一个x0 y0使得 a*x0+b*y0=gcd(a,b);在这里要说明一点,如果方程 a*x+b*y=n有解,则n|(gcd(a,b));

则 a*x*n/gcd(a,b)+b*y0*n/gcd(a,b)=n;

则 x=x0*n/gcd(a,b)  y=y0*n/gcd(a,b); 为方程的一组解

如果方程有解,则又无数解

m1=x+b*t   m2=y-a*t;

t 可以任意,如果不知道怎么推出的话,就把它带进去,就知道了

再回到题目中,现在求出方程n1*x+n2*y=n的一组解 x0 y0

x=x0+t*n2  y=y0-t*n1;

又由于题中都为非负数

x>=0  y>=0从而求出t的范围

t1>=(-x0*n/g)/n2//上取整

t2<=(y0*n/g)/n1//下取整

c1*x+c2*y=num+t(c1*n2-c2*n1);

如果c1*n2-c2*n1>0 t=t1

否则  t=t2

到这里基本上就可以求出此题的大部分,但是有一个细节要注意一下//我在这道题上最主要的搞出来了,但是就是范围老是出错,你要小心哦

200

10 20

20 20

200

20 20

10 20

如果这两组数据你能过得话基本上你就可以AC了

 

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
long n1,n2,c1,c2;
long n;
long gcd(long a,long b,long &x,long &y)
{
 long g,x1,y1;
 if(b==0)
 {
  x=1;
  y=0;
  return a;
 }
 if(b>a)
 {
  g=gcd(b,a,y,x);
 }else
 {
  g=gcd(b,a%b,x1,y1);
  x=y1;
  y=x1-(a/b)*y1;
 }
 return g;
}
int main()
{
 long t1,t2,x,y,x0,y0,g,t;
 while(scanf("%ld",&n)!=EOF)
 {
  if(n==0) break;
  scanf("%ld%ld%ld%ld",&c1,&n1,&c2,&n2);
  g=gcd(n1,n2,x0,y0);
  t1=ceil((-1.0*x0*n)/n2);
  t2=floor((1.0*y0*n)/n1);
  if(t1>t2||n%g!=0)
  {
   printf("failed\n");
   continue;
  }
  if(c1*n2-c2*n1>0)
   t=t1;
  else
   t=t2;
  x=x0*n/g+n2*t/g;
  y=y0*n/g-n1*t/g;
  printf("%ld %ld\n",x,y);
 }
 return 0;
}

你可能感兴趣的:(c,算法,扩展,n2,2010)