整数分割
整数n(100>n>1)が何通りに分割できるか
つまり、正の整数の和で何通りに表せるか
例えば、6の場合は、以下の11通りとなる。
[6],[5,1],[4,2],[4,1,1],[3,3],[3,2,1],[3,1,1,1],
[2,2,2],[2,2,1,1],[2,1,1,1,1],[1,1,1,1,1,1]
動的計画法(Dynamic programming)で解いてみよう
#include <iostream> #include <vector> #include <stdio.h> using namespace std; int dynamic(int m){ int n,a,i; int tmp; //int p[100][100];//静的配列 vector< vector<int> > p;//vector 動的配列 p.resize( m, vector<int>(m) );//vector 動的配列 for(a = 0;a <= m; a++) p[0][a] = 1;//分割し終わったことを示す配列 for(n = 0;n <= m; n++) p[n][1] = 1;//aが1のときは,1しかない for(n = 1;n <= m; n++){ for(a = 2;a <= m; a++){ p[n][a] = p[n][a-1];//aを含まない分割数 if(n >= a) p[n][a] += p[n-a][a];//aを含む分割数 } } return p[m][m]; } void main(){ int n; int tmp; while(1){ scanf("%d",&n); if(n == 0) break; printf("%d\n", dynamic(n) ); } }
100以上の値で実行する場合、signed int型だと、121までしかできなかった
バックトラック法(Backtracking method)でも解いてみる
#include <iostream> #include <vector> #include <stdio.h> using namespace std; int backtrak(int n, int a){ int ret; if(n == 0 || a == 1)//分割しきったとき || 1しかないとき return 1; ret = backtrak(n, a-1);//aより下の結果 if(n >= a)//nがa以上ならば ret += backtrak(n-a,a);//aが解に含まれる場合 return ret; } void main(){ int n; int tmp; while(1){ scanf("%d",&n); if(n == 0) break; printf("%d\n",backtrak(n, n) ); } }
動的計画法と比べてありえないほど時間がかかる