# Dynamic Programming# String Manipulation# Greedy

e881 - Q2 極限運動

🔗 前往 ZeroJudge 原題

題目描述

題目要求計算從起點到終點的路線數量。可以每次走 1 到 m 步,但有些點是禁止經過的。最終輸出到達終點的路線數量,由於數量可能很大,因此以字串形式輸出。

解題思路

本題可以使用動態規劃 (Dynamic Programming) 解決。dp[i] 表示到達第 i 個位置的路線數量。初始化 dp[0] 為 "1",表示從起點出發只有一條路線。然後,從 i = 0n 遍歷每個位置,如果 dp[i] 不為 "-1" (表示該位置可以到達),則可以從該位置向前走 1 到 m 步。對於每個可以到達的位置 i + j (其中 1 <= j <= m),將 dp[i] 加到 dp[i + j] 上。注意,由於路線數量可能很大,需要使用字串來儲存和計算。禁止經過的位置用 "-1" 表示,在計算時跳過這些位置。

複雜度分析

  • 時間複雜度: O(n * m * k),其中 n 是終點位置,m 是最大步數,k 是字串加法的平均長度。
  • 空間複雜度: O(n),用於儲存 dp 陣列。

程式碼

#include <iostream>
using namespace std;
int n,m,d,t;
string dp[1051]={"1"};
string add(string a,string b){
	int tmp[1001]={0},al=a.length(),bl=b.length();
	string c;
	for(int i=0;i<al;++i)tmp[al-i-1]+=a[i]-'0';
	for(int i=0;i<bl;++i)tmp[bl-i-1]+=b[i]-'0';
	for(int i=0;i<1000;++i)
		if(tmp[i]>9){
			++tmp[i+1];
			tmp[i]-=10;
		}
	for(int i=1000;i>=0;--i)
		if(tmp[i]){
			al=i;
			break;
		}
	for(int i=al;i>=0;--i)c+=tmp[i]+'0';
	return c;
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	cin >> n >> m >> d;
	while(d--){
		cin >> t;
		dp[t]="-1";
	}
	for(int i=0;i<=n;++i){
		if(dp[i]=="-1")continue;
		for(int j=1;j<=m&&i+j<=n;++j){
			if(dp[i+j]=="-1")continue;
			dp[i+j]=add(dp[i+j],dp[i]);
		}
	}
	cout << dp[n];
}

Discussion