アルゴリズムはゆっくりと正しい答えに近づく、あなたは正しいアルゴリズムを考える開始する必要があると言うが、その後、一般的な方向でゆっくりと最適化を考えないように、ステップバイステップです。
例えば除算整数この質問を取ります。
質問の意味:
nは1以上の任意の自然数より大きいが、合計は自然数とnにいくつかの小さなに分割することができます。場合解像度のメソッドのN = 7合計14種類:
7 = 1 + 1 + 1 + 1 + 1 + 1 + 1
7 = 1 + 1 + 1 + 1 + 1 + 2
7 = 1 + 1 + 1 + 1 + 3
7 = 1 + 1 + 1 + 2 + 2
7 = 1 + 1 + 1 + 4
7 = 1 + 1 + 2 + 3
7 = 1 + 1 + 5
7 = 1 + 2 + 2 + 2
7 = 1 + 2 + 4
7 = 1 + 3 + 3
7 = 1 + 6
7 = 2 + 2 + 3
7 = 2 + 5
7 = 3 + 4
この問題は、最初のIは続行......再帰的に追加される6を入れ、7-1 = 6を計算するそのような開始列挙1として、7、1からすべての自然数の計数を開始し、7からのみ再帰考えプロセスを繰り返します。
次に、あなたが得ることができます:
あなたはどのように私はそれの重複これらの要素を解決しない......第二と第三を繰り返して見ることができますか?
まず、私は最初の方法は、すべての自然数のうち、すべて7 = X + X + ... + X数を記録するために2次元配列VIS [i]の[j]を使用することだと思うiは自然数、の代わりにJを表し、表示されます例えばVIS第として最初の数データ、[1] [1] = 7、第二VIS [1] [2] = 5、VIS [2] [2] = 1。
そして、すべてのデータを横断する前に、そのない正確に同じ出力を発見した、データの現在の作品のために。
例えば:VIS [1〜7] [2] = 5 1 0 0 0 0 0
VIS [1〜7] [3] = 5 1 0 0 0 0 0
それらのうちの2つは、そう第3の出力を必要としない、同じです。
その後 -
残業で。
私はアイデアをバックアップしませんでした。
あなたが誰かのブログを参照してくださいまで。
彼は言いました -
データの各セットに対して、(回避繰り返しに)多数の前面よりも後方ことを保証しなければなりません。
それから私は目を覚まします。
私は突然感じた:「水平スロット、私は愚かでしたか!」
(言い換えれば、限り、データの各セットが増加しているとして、取り除くために繰り返すことができ、あなたがレコードにVIS配列を使用する必要はありません。)
私はおそらく、コードの改訂プロセスでそれを見ていきます。
ブレークが(I <前の数を列挙するために)循環であれば最初のIで、裁判官を追加しました。
そして、私はこの問題を発見しました!!
私は、前の出力の外観の各発生を再帰的になります。
发现每次的pre其实都是当前的数字,并不是之前的数字。
我将pre和aa[t-1]比较了一下,发现他们两个是一样的。
也就是说,pre现在是当前的数据。
所以只要将pre真正改成前一个数据就好了。
为了防止溢出,我没敢用aa[t-2]和aa[t-1]比较。
还是用了pre,不过放进pre的数据变成了aa[t-1](一开始是i),然后就对了。
贴一下AC代码:
#include<iostream>
#include<algorithm>
#pragma warning(disable:4996)
using namespace std;
int aa[1000];
int n;
void dfs(int t, int a, int pre) {
if (pre > aa[t - 1]) return;
if (a == 0 && aa[1] != n) {//aa[1]!=n的判断是为了消去最后输出的7=7
printf("%d=", n);
for (int i = 1; i < t; i++) {
printf("%d", aa[i]);
if (i != t - 1) printf("+");
}
cout << endl;
}
for (int i = 1; i <= a; i++) {
int k = a - i;
if (k >= 0) {
aa[t] = i;
dfs(t + 1, k, aa[t - 1]);
}
}
}
int main() {
cin >> n;
dfs(1, n, 0);
return 0;
}