GRUB loading, please wait... Error 22无法启动的解决

2011-07-30 • 技术文章

当您发现启动计算机时提示GRUB loading, please wait... Error 22或者是17时,问题可能在于计算机的主引导记录被破坏。此时,计算机无法启动,必须更换新的硬盘才能解决,使用WinPE等工具可以看到磁盘分区。

这时建议使用李大海编写的DiskGen来重写主引导记录(MBR)。可能会遇到重写失败,这时首先重建分区,然后再重写MBR即可解决。

迅雷链接URL不合法一例的解决方案

2010-12-13 • 技术文章

迅雷的thunder协议由于含有可以使某些软件特征识别和翻译的连续字符,从而自身在传播过程中容易产生错误。下面我们就其中一种最为常见的进行分析并解决之。

在迅雷URL复制中,其中的“+”很容易被识别为连接符,从而不能正常显示。所以,当您遇到不合法现象时,请先看一看连接中是否含有空格,如果含有,删去空格并在该处添加一(有的是两个)个“+”字符(不含引号)即可。

利用C程序枚举完全破解王柳数字谜题

2009-04-05 • 技术文章

题目是这样的:下面的竖式中,每个不同的字母代表一个数字(0-9)且它们互异,求出所有可能的结果。

1
2
3
4
5
a b c
d a f g g
+ e g h a
---------
i j g g f

使用C程序如下代码执行,显示所有结果后提示“Problem Solved”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<stdio.h>
int main()
{ int a,b,c,d,e,f,g,h,i,j,use[10]={0},jin1;
for(c=0;c<10;c++)
{ use[c]=1;
    for(g=0;g<10;g++)
     if(use[g]==0)
     { use[g]=1;
       for(a=0;a<10;a++)
       { use[a]=1;
         jin1=(c+g+a)/10;
         f=(c+g+a)%10;
         if(use[f]==0)
         { use[f]=1;
           for(b=0;b<10;b++)
            if(use[b]==0)
            { use[b]=1;
              if(b+jin1>0&&b+jin1<=10)
              { h=10-b-jin1;
                if(use[h]==0)
                { use[h]=1;
                  f=10-1-a;
                  if(use[f]==0)
                  { use[f]=1;
                    for(e=0;e<10;e++)
                     if(use[e]==0)
                     { use[e]=1;
                       j=a+e+1-10;
                       if(j>=0&&use[j]==0)
                       { use[j]=1;
                         for(d=0;d<9;d++)
                          if(use[d]==0&&use[d+1]==0)
                           printf("    %d %d %d
%d %d %d %d %d
+ %d %d %d %d
---------
%d %d %d %d %d
 
",a,b,c,d,a,f,g,g,e,g,h,a,i,j,g,g,f);
                       } }}}}}}}}} 
printf("Problem solved.");
getch();
}

运行结果是,无输出(只输出了Problem Solved)。使用Visual Basic 6.0程序计算,经过计算机4个小时的计算还是无解。

对于如此纷繁复杂的程序,首先应该从较浅层的循环出发,进行输出当前变量操作,以查看是否枚举完毕。像这类问题,往往是由于逻辑问题,而导致枚举过程没有进行完就退出了。

首先检测末位的枚举情况,在下面的代码中加入输出。f=(c+g+a)%10;printf("%d %d %d %d

",c,g,a,f);if(use[f]==0)

输出如下:

1
2
3
4
5
6
7
8
9
10
11
0 1 0 1
0 1 1 2
0 1 2 3
0 1 3 4
0 1 4 5
0 1 5 6
0 1 6 7
0 1 7 8
0 1 8 9
0 1 9 0
Problem solved.

我们不由得疑问:为什么c的取值只有0这个很小的数,而没有更大的枚举?原因一定是在中间时枚举中断了。观察有无控制枚举中断的return,break,continue,发现不存在,于是断定是use数组的问题:忘记归零。

修改后,删除输出语句,发现输出中的某个数很大,一定是输出了地址,或者忘记赋值。发现正是i的位置,原因是d+1事实上并没有赋值为i,于是将i替换为d+1。

输出很多,发现了两个问题:大量重复;末位和不正确。

明明是末位和求了出来,为什么输出时被改变了?一定是内层循环中有修改f之处。果然,f=10-1-a;if(use[f]==0) use[f]=1;便是对f的重新处理。遇到这种情况,不能简单的将后面的语句删除,而要思考出现重复的原因:没有考虑到f在式中出现了两次,重复枚举。注意到a和f都是第一次枚举出来的,于是a+f=9成为枚举的一个约束条件。

删除上面的语句和有关恢复语句use[f]=0;,修改逻辑结构。加入f=(c+g+a)%10;if(a+f==9) if(use[f]==0)判断,成为约束条件。再次运行,不再出现末位和不正确的情况,但仍然出现了重复,例如

1
2
3
4
5
7 8 9
5 7 2 6 6
+ 3 6 0 7
---------
6 1 6 6 2

一组解中i和g重复。下面检查没有进行重复剪枝的问题。for(a=0;a<10;a++) if(use[a]==0) {use[a]=1;中原来没有对a的重复性进行判断。

经过调试,我们得到这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<stdio.h>
int main()
{ int a,b,c,d,e,f,g,h,i,j,use[10]={0},jin1;
for(c=0;c<10;c++)
{ use[c]=1;
    for(g=0;g<10;g++)
     if(use[g]==0)
     { use[g]=1;
       for(a=0;a<10;a++)
       if(use[a]==0)
       { use[a]=1;
         jin1=(c+g+a)/10;
         f=(c+g+a)%10;
         if(a+f==9)
         if(use[f]==0)
         { use[f]=1;
           for(b=0;b<10;b++)
            if(use[b]==0)
            { use[b]=1;
              if(b+jin1>0&&b+jin1<=10)
              { h=10-b-jin1;
                if(use[h]==0)
                { use[h]=1;
                    for(e=0;e<10;e++)
                     if(use[e]==0)
                     { use[e]=1;
                       j=a+e+1-10;
                       if(j>=0&&use[j]==0)
                       { use[j]=1;
                         for(d=0;d<9;d++)
                          if(use[d]==0&&use[d+1]==0)
                           printf("    %d %d %d
%d %d %d %d %d
+ %d %d %d %d
---------
%d %d %d %d %d
 
",a,b,c,d,a,f,g,g,e,g,h,a,d+1,j,g,g,f);
                         use[j]=0;
                       }
                       use[e]=0;   
                  }
                  use[h]=0;
                }
              }
              use[b]=0;
            }
            use[f]=0;
         }
         use[a]=0;
       }
       use[g]=0;
     }
     use[c]=0;
} 
printf("Problem solved.");
getch();
}

输出为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
6 0 2
7 6 3 5 5
+ 4 5 9 6
------------
8 1 5 5 3
    6 9 2
7 6 3 5 5
+ 4 5 0 6
------------
8 1 5 5 3
    6 0 5
7 6 3 2 2
+ 4 2 9 6
------------
8 1 2 2 3
    6 9 5
7 6 3 2 2
+ 4 2 0 6
------------
8 1 2 2 3
    7 0 6
4 7 2 9 9
+ 3 9 8 7
------------
5 1 9 9 2
    7 8 6
4 7 2 9 9
+ 3 9 0 7
------------
5 1 9 9 2
    7 0 9
4 7 2 6 6
+ 3 6 8 7
------------
5 1 6 6 2
    7 8 9
4 7 2 6 6
+ 3 6 0 7
------------
5 1 6 6 2
Problem solved.

共计8组解。

通过这个问题的解决过程,我们体验了一个较为复杂的枚举问题的调试过程。也许读者看起来这些错误都很“幼稚”,但在我们编程的过程中,正是这种“幼稚”的错误一再降低着我们的AC率。因此我们一方面要在写程序时更加小心,另一方面要学会一定的调试技巧,尽可能在短时间内调试成功。