arrows blog

解いた問題などを適当に書いていきます。

AOJ 1237 - Shredding Company

問題概要

tとnumが与えられる。numを分割して和を取ったとき、tとのdiffを最小化し、そのときの和と経路を出力せよ。
もしどのように分割してもtを超えてしまう場合は"error"を、最小のdiffが複数ある場合は"rejected"を出力する。

制約

  • 1 ≤ t ≤ 999999
  • 1 ≤ num ≤ 999999
  • t, numは先頭0はない

解法

全探索する。
再帰してnumを分割して足す。

コード

#include <bits/stdc++.h>
 
using namespace std;
 
#define INF 1e9
 
int t,ans,size,diff;
vector<int> a,path;
map<int,int> mp;
 
int calc(int idx,int N){
  int res = 0, p = 1;
  for(int i = N-1 ; i >= idx ; i--){
    res += a[i]*p;
    p *= 10;
  }
  return res;
}
 
void solve(int idx,int val,vector<int> &v){
  if(idx == size){
    if(val > t) return;
    if(t-val <= diff){
      diff = t-val;
      ans = val; mp[ans]++;
      path = v;
    }
    return;
  }
 
  for(int i = 1 ; i <= size ; i++){
    if(idx + i > size) continue;
    int c = calc(idx,idx+i);
    v.push_back(c);
    solve(idx+i,val+c,v);
    v.pop_back();
  }
}
 
int main(){
  int num;
  while(cin >> t >> num, (t | num)){
    mp.clear(); a.clear(); 
    diff = ans = INF;
    for(int i = 0 ; ; i++){
      if(num == 0) break;
      a.push_back(num%10);
      num /= 10;
    }
    reverse(a.begin(),a.end());
    size = a.size();
    vector<int> v;
    solve(0,0,v);
    if(diff == INF){
      cout << "error" << endl;
    }else{
      if(mp[ans] != 1){
        cout << "rejected" << endl;
      }else{
        cout << ans;
        for(int i = 0 ; i < (int)path.size() ; i++){
          cout << " " << path[i];
        }
        cout << endl;
      }
    }
  }
  return 0;
}