// Greedy, Greedy. #include #include #include using namespace std; /**************************************************************************** * データ型定義 ****************************************************************************/ /** リザルトコード */ enum result_t { RES_OK = 0, ERR_PAY = 1, ERR_GREEDY = 2, }; /** 支払うことが不可能・まだ定まっていないところのデフォルト値 */ #define IMPOSSIBLE 1000000000 /**************************************************************************** * グローバル ****************************************************************************/ /** 現在処理中のケース番号 */ static unsigned ncase = 1; /**************************************************************************** * デバッグ用 ****************************************************************************/ /** * データにエラーが見つかった旨表示して異常終了する。 * * @param message エラー内容 */ static void data_error(const char *message) { cerr << "DATA ERROR (case #" << ncase << "): " << message << endl; assert(false); } /**************************************************************************** * メイン ****************************************************************************/ /** * 問題を解く。 * * @param coins コインの集合 */ result_t solve(const vector& coins) { // 正当性検証 (上昇列になっているかどうか) for(int i = 0; i < coins.size() - 1; i++) if(coins[i] >= coins[i + 1]) data_error("Input data is not an ascending sequence."); // 1 円が払えるかチェック if(coins[0] <= 0) data_error("Zero or negative coin"); else if(coins[0] > 1) return ERR_PAY; // cannot pay some amount if(coins.size() == 1) // 自明なケース return RES_OK; // DP と貪欲法用の table unsigned limit = coins[coins.size() - 1] + coins[coins.size() - 2]; // naive vector dp(limit, IMPOSSIBLE), greedy(limit, IMPOSSIBLE); // DP dp[0] = 0; for(unsigned amount = 1; amount < limit; amount++) for(int i = 0; i < coins.size(); i++) { if(coins[i] > amount) break; dp[amount] = min(dp[amount], dp[amount - coins[i]] + 1); } // Greedy algorithm for(unsigned amount = 0; amount < limit; amount++) { unsigned rem = amount, count = 0; for(int i = coins.size() - 1; i >= 0; i--) { count += rem / coins[i]; rem = rem % coins[i]; } #ifdef _DEBUG cerr << "amount=" << amount << ", c=" << count << "/r=" << rem << " | DP=" << dp[amount] << endl; #endif if(rem) assert(false); // 払えない金額があるが、上ではじかれているはず? else greedy[amount] = count; } // Checking loop for(unsigned amount = 0; amount < limit; amount++) if(greedy[amount] != dp[amount]) { #ifdef _DEBUG cerr << "failed at amount=" << amount << endl; #endif return ERR_GREEDY; } return RES_OK; } /** * プログラムのエントリポイント。 */ int main() { unsigned n; while(cin >> n, n) { // Input vector coins; int c; while(n--) { cin >> c; coins.push_back(c); } // Solve and output const result_t res = solve(coins); cout << "Case #" << ncase++ << ": "; switch(res) { case RES_OK: cout << "OK"; break; case ERR_PAY: cout << "Cannot pay some amount"; break; case ERR_GREEDY: cout << "Cannot use greedy algorithm"; break; default: assert(false); } cout << endl; } }