AOJ : 1248 - The Balance

問題概要

http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=1248


1つの薬、2種類のおもり(A,B)、左と右に皿がついた天秤、がある。
各おもりの個数に制限はなく、何個でも使ってよい。
おもりAの個数x・重さa、おもりBの個数y・重さbとするとき、次のようになるx、yを求めるのがこの問題。

  • 次の3条件の内、どれかを満たす
    • 薬を左の皿に、おもりAをx個左の皿に、おもりBをy個右の皿に置いたとき、つり合いが取れる
    • 薬を右の皿に、おもりAをx個左の皿に、おもりBをy個右の皿に置いたとき、つり合いが取れる
    • 薬を右の皿に、おもりAをx個左の皿に、おもりBをy個左の皿に置いたとき、つり合いが取れる
  • このとき、(x+y)が最小になる
  • (x+y)が最小になるものが複数ある場合、(ax+by)が最小になるものを選択

アルゴリズム

おもりAの個数をループで決めてやれば、おもりBの個数も自然に決定されるので、これで解く。
このときのAの個数の上限は、考えるのが面倒だったため、適当に100000にした。

プログラム

#include <stdio.h>

#define INF 999999999

//答えを更新すべきなら更新する
void updateAns(int a,int b,int ta,int tb,int *ans_a,int *ans_b){
  if(*ans_a + *ans_b > ta + tb){
    *ans_a = ta;
    *ans_b = tb;
  }
  else if(*ans_a + *ans_b == ta + tb){
    if(a * ta + b * tb < a * (*ans_a) + b * (*ans_b)){
      *ans_a = ta;
      *ans_b = tb;
    }
  }
}

int main(void){
  int i,j;
  int a,b,d;
  int ta,tb,ans_a,ans_b;

  while(scanf("%d%d%d",&a,&b,&d) && (a||b||d)){
    ans_a = INF;
    ans_b = INF;

    for(i=0;i<=100000;i++){
      //左の皿にdを乗せる
      if((a * i + d) % b == 0){
        ta = i;
        tb = (a * i + d) / b;
        updateAns(a,b,ta,tb,&ans_a,&ans_b);
      }
      //右の皿にdを乗せる
      if(a * i >= d && (a * i - d) % b == 0){
        ta = i;
        tb = (a * i - d) / b;
        updateAns(a,b,ta,tb,&ans_a,&ans_b);
      }
      //右の皿にdを乗せて,計測用のおもりは全て左
      if(a * i <= d && (d - a * i) % b == 0){
        ta = i;
        tb = (d - a * i) / b;
        updateAns(a,b,ta,tb,&ans_a,&ans_b);
      }
    }

    printf("%d %d\n",ans_a,ans_b);
  }

  return 0;
}