Matches UVA - 11375 遞推+高精度加法

題目鏈接

 We can make digits with matches as shown below:

Given N matches, find the number of different numbers representable using the matches. We shall only make numbers greater than or equal to 0, so no negative signs should be used. For instance, if you have 3 matches, then you can only make the numbers 1 or 7. If you have 4 matches, then you can make the numbers 1, 4, 7 or 11. Note that leading zeros are not allowed (e.g. 001, 042, etc. are illegal). Numbers such as 0, 20, 101 etc. are permitted, though.

分析:把"己經使用過的火柴數1" 看成狀態,可以得到一個圖。從前往後每添加一個數字x , 就從狀態i 轉移到i+c[x] ,其中c[x]代表數字x 需要的火柴數。當i=0 的時候不允許使用數字0。(最後當n>=6 時,給答案單獨加上1,代表整數0) 。從結點。和x (X>0) 出發的邊分別如圖2-3 (a) 和圖2-3 (b) 所示。


令d(i)爲從結點。到結點i 的路徑條數,則答案j{n)=d(1 )+d(2)+d(3)+.. .+d(n) (因爲火柴不必用完,所以使用的火柴數目可能是1 , 2 , 3 , ...,n)。程序實現時,我們可以按照從小到大的順序用d(i)更新所有的d(i+c[j])(j 取遍數字。~9) ,
代碼如下(請注意,下面的代碼中略去了高精度運算)。d[i] 爲恰好用工根火柴可以組成的正整數(不含0)

方法一:用vector寫了一個高精度。

#include <iostream>
#include <vector>
using namespace std;
const int num[10] = {6,2,5,5,4,5,6,3,7,6}; 
const int N = 2000;
vector<int> d[N+5];

void add(vector<int>& a,const vector<int> b){
	vector<int> res;
	res.reserve(500);
	for(int i = 0, r = 0; i < a.size() || r || i < b.size(); i++){
		int x = i < a.size() ? a[i] : 0;
		int y = i < b.size() ? b[i] : 0;
		int s = x + y + r;
		r = s / 10;
		res.push_back(s%10);
	}
	a.assign(res.begin(), res.end());
}

int main(int argc, char** argv) {
	for(int i = 1; i <= N; i++)
			d[i].assign(1, 0);
	d[0].assign(1,1);
	for(int i = 0; i <= N; i++)
		for(int j = 0; j < 10; j++)
			if(!(!i && !j) && i+num[j] <= N) //i=j=O 時不允許轉移
				add(d[i+num[j]], d[i]);
	add(d[6],vector<int> (1,1)); //加入沒被計入的0
	for(int i = 2; i <= N; i++)
		add(d[i],d[i-1]);		
	int n;
	while(~scanf("%d",&n)){	 
		for(int i = d[n].size()-1; i >= 0; i--)
			cout<< d[n][i];
		cout<< "\n";
	} 	
	return 0;
}

方法二:數組實現。 

#include <iostream>
#include <cstring>
#include <algorithm> 
using namespace std;
const int num[10] = {6,2,5,5,4,5,6,3,7,6}; 
const int N = 2000;
int len[N+5], d[N+5][500];

void add(int a,int b){
	len[a] = max(len[a], len[b]);
	for(int i = 0; i  <= len[a]; i++){
		d[a][i] += d[b][i];
		d[a][i+1] +=  d[a][i]/10;
		d[a][i] %= 10;
	}
	if(d[a][len[a]+1] > 0) len[a]++;
}

int main(int argc, char** argv) {
	int n;
	d[0][0] = 1;
	for(int i = 0; i <= N; i++)
		for(int j = 0; j < 10; j++)
			if(!(!i && !j) && i+num[j] <= N )//i=j=0 時不允許轉移
				add(i+num[j], i);
	add(6,0); //加入沒被計入的0,+1
	for(int i = 2; i <= N; i++)
			add(i, i-1);
	while(~scanf("%d",&n)){								 
		for(int i = len[n]; i >= 0; i--)
			printf("%d",d[n][i]);
		printf("\n");
	} 	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章