# Dynamic Programming# Greedy# Array

f176 - 湊不到錢大作戰

🔗 前往 ZeroJudge 原題

題目描述

題目要求找出小於等於 k 且最接近 k 的一個數,這個數無法由兩個給定的錢幣面額 mn 湊成。如果所有小於等於 k 的數都可以被 mn 湊成,則輸出 "good"。

解題思路

本題可以使用動態規劃的思想來解決。建立一個布林陣列 a,大小為 k+1,其中 a[i] 表示金額 i 是否可以被 mn 湊成。初始化 a[0]true,表示金額 0 可以被湊成(不使用任何錢幣)。然後,從 0 到 k-nk-m 遍歷,如果 a[i]true,則將 a[i+n]a[i+m] 設為 true,表示金額 i+ni+m 也可以被湊成。最後,從 k 開始倒序遍歷 a 陣列,找到第一個 a[i]false 的索引 i,這個 i 就是答案。如果遍歷完整個陣列都沒有找到 false,則輸出 "good"。

複雜度分析

  • 時間複雜度: O(k)
  • 空間複雜度: O(k)

程式碼

#include <iostream>
using namespace std;
int n,a[1000005],k,m,t;
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	cin >> t;
	while(t--){
		cin >> k >> n >> m;
		if(n==1||m==1){
			cout << "good\n";
		}
		else{
			for(int i=0;i<=k;++i){
				a[i]=0;
			}
			a[0]=1;
			int ans=0;
			for(int i=0;i<=k-n;++i){
				if(a[i])a[i+n]=1;
			}
			for(int i=0;i<=k-m;++i){
				if(a[i])a[i+m]=1;
			}
			for(int i=k;i>0;--i){
				if(a[i]==0){
					ans=i;
					break;
				}
			}
			if(ans){
				cout << ans << "\n";
			}
			else{
				cout << "good\n";
			}
		}
	}
}

Discussion