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;
}

 

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