一、枚举:1753、2965
二、贪心:2109、2586
三、最小生成树:2485、1258
四、排序:2388
五、深度优化搜索:1321、2251
六、广度优化搜索:3278、1426
七、简单搜索技巧和剪枝:2676
八、背包问题:1837
九、拓扑排序:1094
十、最短路径算法:1062、1125、2240
十一、哈夫曼树:3253
十二、哈希表和二分查找等高效查找法:2151、2503
本周继续练习枚举。
北大POJ2956:Repeatless Numbers
题目
分析
输入:输入测试文件将包含多个测试用例,每个测试用例由包含整数 n 的单个行组成,其中 1 ≤ n ≤ 1000000。文件末尾由 n = 0 的测试用例标记,不应进行处理。
输出:对于每个输入情况,程序应在一行上打印第 n 个无重复数字。
示例输入:
25
10000
0
示例输出:
27
26057
我的思路:
算是暴力解法,枚举+分类判断是否满足条件。
进阶
1.用BFS:
完全没想到还能用BFS。
——初始状态为1~9,在初始状态的后面不断地添加0~9可以得到下一层状态,在对第二层状态不断地进行扩展,知道扩展到第1000000个状态为止。每一个状态包含两个属性value和digit,value为状态的值,假设为134,则digit为11010,d[i]=1表示i在value中,在数字134后添加0~9中的数字时(假设添加的数字为1),如何判断1是否在134中出现过呢,value=1,则digit = 10 ,将11010与10做与操作即11010&10,若结果不等于0,这说明1在134中存在,否则不存在。
2.考虑一些情况来减少枚举:
创建一个数组,保存每一位,判断有无重复数字(这里感觉有点像第一章说的位存储)。比如对于一个数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 }