# Breadth-First Search# Graph# Dynamic Programming

d663 - 11730 - Number Transformation

🔗 前往 ZeroJudge 原題

題目描述

題目要求計算將數字 S 轉換為數字 T 所需的最少步驟數。轉換的規則是,每次可以將當前數字加上其一個質因數。如果無法轉換,則輸出 -1。

解題思路

這題可以建模成一個圖,其中每個數字是一個節點,如果一個數字可以透過加上其質因數轉換到另一個數字,則這兩個節點之間存在一條邊。然後,問題就變成了在圖中找到從 S 到 T 的最短路徑。

程式碼中,s[i][j] 儲存了數字 i 的第 j 個質因數。sdp[st][it] 儲存了從 st 出發到 it 的最小步驟數。sdfs 函數使用深度優先搜尋 (DFS) 進行探索,並更新 sdp 陣列。雖然使用了 DFS,但其核心思想是動態規劃,避免重複計算。

在主函數中,首先預處理出每個數字的質因數,然後使用 DFS 計算所有數字之間的最小步驟數。最後,對於每個測試案例,查詢 sdp[S][T] 的值,如果為初始值 1000,則表示無法到達,輸出 -1,否則輸出 sdp[S][T]

複雜度分析

  • 時間複雜度: O(1000 * 1000 * 質因數數量) 最壞情況下,需要遍歷所有數字,並對每個數字計算其質因數,然後進行 DFS 探索。
  • 空間複雜度: O(1000 * 1000) 主要用於儲存 sdp 陣列。

程式碼

#include <iostream>
using namespace std;
int s[1005][1005],S,T,ca,sdp[1005][1005];
void sdfs(int it,int st,int v){
	if(it>1000)return;
	if(sdp[st][it]<=v)return;
	sdp[st][it]=v;
	for(int i=s[it][0];i>=1;--i){
		sdfs(it+s[it][i],st,v+1);
	}
}
int main(){
	//cin.tie(0); ios::sync_with_stdio(false);
	for(int i=1;i<=1000;++i){
		int it=1;
		for(int j=2;j<=i/2;++j){
			if(i%j==0){
				int ac=1;
				for(int k=2;k<=j/2&&ac;++k){
					if(j%k==0)ac=0;
				}
				if(ac){
					s[i][it]=j;
					++it;
				}
			}
		}
		s[i][0]=it-1;
	}
	for(int i=1;i<=1000;++i){
		for(int j=1;j<=1000;++j){
			sdp[i][j]=1000;
		}
		sdfs(i,i,0);
	}
	while(cin >> S >> T){
		if(S+T==0)break;
		cout << "Case " << ++ca << ": ";
		if(sdp[S][T]==1000){
			cout << "-1\n";
		} 
		else{
			cout << sdp[S][T] << "\n";
		}
	}
}

Discussion