1.列挙: 1753、2965
2. 貪欲: 2109、2586
3. 最小スパニングツリー: 2485、1258
4. 仕分け: 2388
5.詳細な最適化検索: 1321、2251
6. 幅の最適化された検索: 3278、1426
7. 簡単な検索テクニックと枝刈り: 2676
8. ナップサック問題: 1837年
9. トポロジカルソート: 1094
10. 最短パスアルゴリズム: 1062、1125、2240
11. ハフマンツリー: 3253
12. ハッシュテーブルや二分探索などの効率的な検索方法:2151、2503
今週も列挙の練習を続けます。
北京大学 POJ2956: 繰り返されない数字
トピック
分析する
入力: 入力テスト ファイルには複数のテスト ケースが含まれます。各テスト ケースは、整数n (1 ≤ n ≤ 1000000)を含む 1 行で構成されます 。ファイルの終わりは、 n = 0 のテスト ケースによってマークされているため、処理しないでください。
出力: 各入力ケースについて、プログラムはn 番目 の一意の番号を1 行に 出力する必要があります。
入力例:
25
10000
0
出力例:
27
26057
私の思考回路:
条件を満たしているかどうかを判断する列挙+分類という乱暴な解決法です。
高度
1.BFSを使用します。
BFS を使用するとはまったく予想していませんでした。
——初期状態は 1 ~ 9 で、初期状態の後に 0 ~ 9 を連続的に加算することで次の階層状態を取得でき、拡張が 1000000 番目の状態に達するまで 2 番目の階層状態が継続的に拡張されます。各状態には 2 つの属性値と数字が含まれます。値は状態の値です。134 であると仮定すると、数字は 11010 になります。d[i]=1 は、値に 0 ~ 9 の数字が追加されることを意味します。数字 134 (加算した数を 1 とします)、134 に 1 が出現したかどうかを判断する方法、値 = 1、桁 = 10、および 11010 と 10 の演算は 11010&10 です。結果が 0 に等しくない場合、これは、134 の中に 1 が存在することを意味し、それ以外の場合は存在しません。
2.列挙を減らすためにいくつかのケースを考慮します。
配列を作成し、各ビットを保存し、繰り返しの数値があるかどうかを判断します(ここは第 1 章で述べたビットの保存に少し似ています)。たとえば、数値 128267 の場合、その 2 桁目 (右から左に数えて) が 4 桁目と同じである場合、1282** の形式の数値を列挙する必要はなく、次から直接列挙できます。 128300。これにより、列挙時間が短縮されます。
コード
1.BFS を使用します。
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 using namespace std;
5
6 const int N = 1000000;
7 struct Number
8 {
9 int value; //数字的十进制表示
10 int digit; //二进制序列,从右往左数digit[i]==1表示value中有i
11
12 Number(){}
13 Number(int v, int d):value(v), digit(d){}
14 }ans[N+10];
15
16 int main()
17 {
18 for(int i=1; i<10; i++)
19 ans[i] = Number(i, 1<<i);
20
21 int k = 1;
22 for(int cur=10; cur<=N; k++)
23 {
24 int v = ans[k].value;
25 int d = ans[k].digit;
26
27 for(int i=0; i<10; i++)
28 {
29 if( !(d & (1<<i)))
30 ans[cur++] = Number(v*10+i, d|1<<i);
31 }
32 }
33
34 int n;
35 while(scanf("%d", &n)==1 && n)
36 printf("%d\n", ans[n].value);
37 return 0;
38 }
2. 列挙を減らします。
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 using namespace std;
5
6 const int N = 1000000;
7 int ans[N+1] = {0};
8 int power[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
9
10 void init()
11 {
12 int d[10]; //存储数字x
13 int v[10]; //v[i]表示数字i是否在x中出现过
14 int cur = 1;
15 int x, y=1;
16 while(cur<=N)
17 {
18 x = y;
19 memset(v, -1, sizeof(v));
20 memset(d, 0, sizeof(d));
21
22 int i, j;
23 for(i=0; x!=0; i++)
24 {
25 d[i] = x % 10;
26 if(v[d[i]]!=-1)
27 break;
28 v[d[i]] = i;
29 x /= 10;
30 }
31 if(!x)
32 {
33 ans[cur++] = y;
34 y++;
35 }
36 else
37 {
38 j = v[d[i]];
39 for(i--; i>=j; i--)
40 x = x*10+d[i];
41 x++;
42 y = x*power[j];
43 }
44 }
45 }
46
47 int main()
48 {
49 init();
50 int n;
51 while(cin>>n && n)
52 cout<<ans[n]<<endl;
53 return 0;
54 }