题意:求用n个火柴能组成几个非负整数,火柴不必用完,前导0是不能存在的
思路:把“已经用过火柴数i”表示状态,以后每添加一个数字x就转移状态i到i+c[x](c[x]表示x 用到的火柴数),因为没有前导0,所以状态为0的时候是不能添加数字0的(最后当n>=6的时候再添加一个代表0)
令d[i]表示到i状态的个数,利用加法原理,因为可以不必用完火柴,所以答案是:
d[1]+...d[n]
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 510; struct node{ int p[MAXN]; int len; node(){ memset(p,0,sizeof(p)); len = 0; } node(int a){ p[0] = a; len = 1; } node operator +(const node &a) const{ node b; b.len = max(len,a.len); for (int i = 0; i < b.len; i++){ b.p[i] += p[i] + a.p[i]; b.p[i+1] = b.p[i] / 10; b.p[i] %= 10; } if (b.p[b.len] > 0) b.len++; return b; } void out(){ if (len == 0) printf("0\n"); else { for (int l = len-1; l >= 0; l--) printf("%d",p[l]); printf("\n"); } } }d[2005]; int c[] = {6,2,5,5,4,5,6,3,7,6}; int main(){ d[0].p[0] = 1,d[0].len = 1; for (int i = 0; i < 2001; i++)//前导0不行 for (int j = 0; j < 10; j++) if (!(i==0 && j==0) && i+c[j] < 2001) d[i+c[j]] = d[i+c[j]] + d[i]; d[6] = d[6] + node(1); for (int i = 2; i < 2001; i++) d[i] = d[i] + d[i-1]; int n; while (scanf("%d",&n) != EOF && n > 0) d[n].out(); return 0; }
原文:http://blog.csdn.net/u011345136/article/details/19126309