You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

104 lines
4.2 KiB

2 years ago
#include <bits/stdc++.h>
//题意分析https://blog.csdn.net/xienaoban/article/details/52164099
using namespace std;
//d:d块磁盘,s:1<=s<=64数据被划分成大小为s比特的数据块
//b:b个数据块 b in range(1,101)
int d, s, b, kase = 0;
//type:校验的种类E->偶校验 O->奇校验
char type;
//每块磁盘上8的含义数据的内容之所以是8000是因为每个字符是8个字节
char tab[8][8000];
//检查是不是合法
bool Fix() {
for (int i = 0; i < s * b; ++i) {
//s比特的数据块 * 数据块个数=所有的比特数据个数
// ++i 表示先加1再循环与i++的区别在于:
// https://blog.csdn.net/qq_41620518/article/details/88066963
int sum = 0, cnt = 0, x_no;
for (int j = 0; j < d; ++j) {
if (tab[j][i] == '1') ++sum;//求1的个数
if (tab[j][i] == 'x') ++cnt, x_no = j;
//如果存在x即明确的错误标识那么cnt记录错误的个数,同时记录是哪个位置出错了~
}
sum %= 2; //求最终校验位是0还是1看看是不是有问题
if (cnt >= 2) return false;//有两个以上错误就没办法了
else if (cnt == 1) //如果还可以挽救的话
{
if (sum)//如果是1
if (type == 'E') //如果是偶校验,表示缺少一个1那么肯定是出错标识的那个位置是1
tab[x_no][i] = '1';
else tab[x_no][i] = '0';//如果是奇校验位表示1的数量正常出错标识那个的位置是0
else //如果是0
if (type == 'E') tab[x_no][i] = '0'; //如果是偶校验位出错标识的那个位置是0
else tab[x_no][i] = '1';//如果是奇校验位出错标识的那个位置是1
} else if (cnt == 0) {//没有明确出错标识,检查吧
if (type == 'E' && sum == 1) return false; //偶校验,但校验码是奇数,表示有错误
if (type == 'O' && sum == 0) return false; //奇校验,但校验码是偶数,表示有错误
}
}
return true;
}
//输出数据
void out_data() {
int sum = 0, bit_cnt = 0;
//b个数据块
for (int i = 0; i < b; ++i) {
int except = i % d; //排除哪一块磁盘上是存在parity
//d块磁盘
for (int j = 0; j < d; ++j) {
if (j == except) continue; //遍历每一块磁盘时,遇到校验块就跳过
//数据是s比特的数据块
//然后还有一点是输出数据的时候4个bit转化为一个十六进制。
//刚开始做题认为每个数据块输出一个整数这需要2^5*64这么大的数来存储
//难道要用大整数类?后来一想,可以每一个十六进制位输出一次便可。
for (int k = i * s; k < i * s + s; ++k) { //遍历每一个数据位
bit_cnt = (bit_cnt + 1) % 4;
if (tab[j][k] == '0') sum *= 2;
else sum = sum * 2 + 1;
if (!bit_cnt) {
printf("%X", sum);
sum = 0;
}
}
}
}
//有尾巴需要输出的话
if (bit_cnt) {
int over = 4 - bit_cnt;
sum = sum * (1 << over);
printf("%X", sum);
}
printf("\n");
}
int main() {
//https://www.cnblogs.com/cytus/p/7763569.html
//对于标准输入和输出的缓冲同步进行禁止,防止程序超时
ios::sync_with_stdio(false);
//真是能省就省啊一路初始化数组一般输入数据如果数据是0或者小于0那么停止。
while (memset(tab, 0, sizeof(tab)), cin >> d && d) {
//d:d个磁盘
//s:数据被划分成大小为s比特的数据块
//b: 1<=b<=100个数据块
//type:校验的种类E表示偶校验O表示奇校验
cin >> s >> b >> type;
for (int i = 0; i < d; ++i)
cin >> tab[i]; //在录入磁盘中的数据
//校验失败
if (!Fix())
printf("Disk set %d is invalid.\n", ++kase);
else {
//校验成功
printf("Disk set %d is valid, contents are: ", ++kase);
//输出数据
out_data();
}
}
return 0;
}