习题4-7 RAID技术 UVa509

算法竞赛入门经典(第2版)第4章 函数和递归

题4-7RAID技术  UVa509

感悟。

1、从网站下载英文原题,重点在看输入输出数据与格式。

2、准备不看书中中文,完成此题。

3、英文题目信息量比较大,异或看懂了,但‘E’‘O’还要费些时间才能弄懂。

4、even parity(偶校验),odd parity(奇校验)弄懂了,根据被传输的一组二进制代码的数位中“1”的个数是奇数或偶数来进行校验。采用奇数的称为奇校验,反之,称为偶校验。

5、样例中的第二个例子没搞懂,怎么会是Disk set 2 is invalid.所以一直没法开始编码。

6、读了一遍书中的中文,发现没有帮助,题目没读懂,编程就没法开始,上网搜索,看看有没帮助。

7、一圈搜索下来,发现有人问同样的问题,但没有解决。大部分都没有提及5、中的问题。

8、歇一歇,突然一个念头想过,当然受到http://blog.csdn.net/thudaliangrx/article/details/50700688启发,注意RAID数据保存出错的情况有两种:
1、某列有x的情况下,只能有一个x,否则无法恢复数据。
2、某列没有x的情况下,需要能通过校验。

上述说法,最有用的是第二点,例子2的问题在与校验错误,xx是个障眼法。

9、此处对例子2为什么invalid进行详细分析:

输入:

3 2 5
E
0001111111
0111111011
xx11011111

输出:

Disk set 2 is invalid.

例子2数据分析:

disk1 disk2 disk3

00      01      xx     此行能分析出数据,xx是01

01      11      11     此行每块数据第一位 数1的个数(2个1),第二位(3个1),校验出错

11      11      01     此行每块数据第一位 数1的个数(2个1),第二位(3个1),校验出错

11      10      11     此行每块数据第一位 数1的个数(3个1)第二位(2个1),校验出错

11      11      11     此行每块数据第一位 数1的个数(3个1)第二位(3个1),校验出错

‘E’偶校验,要求有每行的每一位上1的个数和要是偶数,故此例中的xx是障眼法,第一行数据没有出错。

11、An arrangement of disks is invalid if a parity error is detected, or if any data block cannot be
reconstructed because two or more disks are unavailable for that block.数据无效,提到了两种情况,一是校验位出错,二是有两块以上的硬盘数据出错(本人认为是同一行上的数据出错)。

整个题目中还有一个隐含错误,没有x的情况下,需要能通过校验。这点是通过例子2体现出来的。真是难啊,一堆搜索,能把例子2讲明白的,只有本文了。希望对后来者有所帮助。

12、题目读下来,没有问题后,可以放心开始编码了。

13、按部就班,第一步检查校验位,第二步检查两个以上硬盘同行同位出错,第三步检查奇偶校验出错。

14、若硬盘数据有效,修复硬盘。

15、提交WA,需要查代码了,时间不会比编码少。

16、找到http://blog.csdn.net/thudaliangrx/article/details/50700688,提交代码AC,接下来,进行对拍处理。

17、重读An arrangement of disks is invalid if a parity error is detected, or if any data block cannot be
reconstructed because two or more disks are unavailable for that block.才发现是两个错误,一是校验出错,而不是校验位出错,二是同一位上有两个或多个数据出错,前面的理解有重大问题。

18、修改,提交AC,此时2016-11-10 7:50 同时发现http://blog.csdn.net/thudaliangrx/article/details/50700688中的AC代码,有重大问题,样例中的例子3无法通过,显然在UVa的数据库中,没有例子3的测试数据。

19、将本人的输入输出数据提供如下:

输入数据:

5 2 5
E
0001011111
0110111011
1011011111
1110101100
0010010111
5 2 5
E
x001011111
0110111011
1011011111
1110101100
0010010111
5 2 5
E
0001011111
0110111011
x011011111
1110101100
0010010111
5 2 5
E
0001011111
0110111011
x011011111
x110101100
0010010111
5 2 5
E
0001011111
0110111011
1011011111
x110101100
00x0010111
3 2 5
E
0001111111
0111111011
xx11011111
3 5 1
O
11111
11xxx
x1111
0

输出数据:

Disk set 1 is valid, contents are: 6C7A79EDFC
Disk set 2 is invalid.
Disk set 3 is valid, contents are: 6C7A79EDFC
Disk set 4 is invalid.
Disk set 5 is valid, contents are: 6C7A79EDFC
Disk set 6 is invalid.
Disk set 7 is valid, contents are: FFC

附上AC代码,编译环境Dev-C++4.9.9.2

#include <stdio.h>
#include <string.h>

int d,s,b;//2<=d<=6  1<=s<=64 1<=b<=100
char parity;
char disk[10][10000];//磁盘数据
char info[100000];
char content[100000];
int infocount;
int contentcount;
int main(){
    int i,j,k;
    char str[10];
    int be;//非校验位
    int bcount;
    int kase=0;
    int onecount;//数1的个数
    int eop; //even odd parity
    int eoe;//even odd error
    int need;
    int tmpi;
    char tmpc;
    int eox;
    while(scanf("%d",&d)&&d){//d=0退出
        scanf("%d%d",&s,&b);
        scanf("%s",str);
        parity=str[0];//'E' 'O'
        for(i=0;i<d;i++){//硬盘数据读取
            scanf("%s",disk[i]);
        }
        kase++;
               
        //检查统一行上,同一位上是否有两个或以上数据出错
        be=0;
        for(j=0;j<b;j++){//s个位,取出一同位
            for(k=0;k<s;k++){
                bcount=0;
                for(i=0;i<d;i++){
                    if(disk[i][j*s+k]=='x'){
                        bcount++;
                        if(bcount>=2){
                            be=1;
                            break;
                        }
                    }
                }
                if(be==1)
                    break;
            }
            if(be==1)
                break;
        }
        if(be==1){
            printf("Disk set %d is invalid.\n",kase);
            continue;
        }
        
        //奇偶校验是否正确,遇到'x',跳过该位
        if(parity=='E')//偶数个1
            eop=0;
        else//奇数个1
            eop=1;
        eoe=0;
        for(j=0;j<b;j++){
            for(k=0;k<s;k++){
                onecount=0;
                eox=0;
                for(i=0;i<d;i++){
                    if(disk[i][j*s+k]=='1'){
                        onecount++;
                    }else if(disk[i][j*s+k]=='x'){
                        eox=1;
                    }
                }
                if(eox!=1&&onecount%2!=eop){//校验失败
                    eoe=1;
                    break;
                }
            }
            if(eoe==1)
                break;
        }
        if(eoe==1){
            printf("Disk set %d is invalid.\n",kase);
            continue;
        }
        
        //硬盘数据有效,数据进行处理
        //修补数据
        for(j=0;j<b;j++){
            for(k=0;k<s;k++){
                onecount=0;
                need=0;
                for(i=0;i<d;i++){
                    if(disk[i][j*s+k]=='1'){
                        onecount++;
                    }
                    if(disk[i][j*s+k]=='x'){
                        need=1;
                        tmpi=i;
                    }
                }
                if(need){//修补数据
                    if(onecount%2==eop)
                        disk[tmpi][j*s+k]='0';
                    else
                        disk[tmpi][j*s+k]='1';
                }
            }
        }
        
        
        // 数据内容读取
        infocount=0;
        for(j=0;j<b;j++){
            for(i=0;i<d;i++){
                for(k=0;k<s;k++){
                    if(j%d!=i){
                        info[infocount]=disk[i][j*s+k];
                        infocount++;
                    }
                }
            }
        }
        if(infocount%4!=0){
            k=4-infocount%4;
            for(i=0;i<k;i++){
                info[infocount]='0';
                infocount++;
            }
        }
        info[infocount]='\0';//字符串结束标志
        //二进制转十六进制
        contentcount=0;
        for(i=0;i<infocount;i++){
            if(i%4==0){
                //十六进制开始
                k=0;
                k+=(info[i]-'0')*2*2*2;
            }else if(i%4==1){
                k+=(info[i]-'0')*2*2;
            }else if(i%4==2){
                k+=(info[i]-'0')*2;
            }else if(i%4==3){
                k+=info[i]-'0';
                //十六进制结束
                switch(k){
                    case 10:
                        tmpc='A';
                        break;
                    case 11:
                        tmpc='B';
                        break;
                    case 12:
                        tmpc='C';
                        break;
                    case 13:
                        tmpc='D';
                        break;
                    case 14:
                        tmpc='E';
                        break;
                    case 15:
                        tmpc='F';
                        break;
                    default:
                        tmpc=k+'0';
                }
                content[contentcount]=tmpc;
                contentcount++;
            }
        }
        content[contentcount]='\0';//字符串结束
        contentcount++;
        printf("Disk set %d is valid, contents are: %s\n",kase,content);
    }
    return  0;
}





  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值