和普通匹配不太一样的主要是人的DNA序列是环状的,所以可以把人的DNA序列,也就是主串T复制扩大一倍再和病毒DNA进行匹配。
这道题本身没什么难的,自己耗了点时间主要是在输入上……太久没写字符串相关了,顺便复习了下scanf,自己写了点遗忘的要点放在了末尾。
输入要求:多组数据,每组数据有1行,为序列A和B,A对应病毒的DNA序列, B对应人的DNA序列。A和B都为‘0’时输入结束。
输出要求:对于每组数据输出1行,若患者感染了病毒输出“YES”,否则输 出“NO”。
-
头文件
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXSIZE 50 struct String{//由于每次求长度太麻烦所以我声明了一个带长度的结构 char string[MAXSIZE]; int size;//存储字符串长度 }; -
计算nextval数组
void getNextval(String T, int* nextval) { int i, j; i = 1; j = 0; nextval[1] = 0; while (i < T.size) { if (j == 0 || T.string[i-1] == T.string[j-1]) { ++i; ++j; if (T.string[i-1] != T.string[j-1]) nextval[i] = j; else nextval[i] = nextval[j]; } else j = nextval[j]; } } -
KMP模式匹配
int indexKmp(String S,String T) { int i = 1; int j = 1; int nextval[MAXSIZE]; getNextval(T, nextval); while (i <= S.size && j <= T.size) { if (j == 0 || S.string[i-1] == T.string[j-1]) {//当两字母相等时继续 ++i; ++j; } else { j = nextval[j];//j回到合适位置,i不变 } } if (j > T.size) return i - T.size; return -1; } -
扩大人DNA序列
void doubleString(String *B) { for (int i = B->size , j = 0; j < B->size; i++, j++) B->string[i] = B->string[j]; B->size *= 2; return; }//将人DNA串扩大 -
主函数
int main() { String B[MAXSIZE];//存储人的DNA序列 String A[MAXSIZE];//存储病毒的DNA序列 bool outcome[MAXSIZE];//存储匹配的结果 int i = 0; scanf_s("%s", A[0].string,MAXSIZE); scanf_s("%s", B[0].string,MAXSIZE); A[0].size = strlen(A[0].string); B[0].size = strlen(B[0].string); doubleString(&B[0]); while (A[i].string[0] != '0' && B[i].string[0] != '0') { if (indexKmp(B[i], A[i])!=-1) outcome[i] = true; else outcome[i] = false; i++; scanf_s("%s", A[i].string,MAXSIZE); scanf_s("%s", B[i].string,MAXSIZE); A[i].size = strlen(A[i].string); B[i].size = strlen(B[i].string); doubleString(&B[i]); } for (int n = 0; n < i; n++) { if (outcome[n]) printf("YES\n"); else printf("NO\n"); } return 0; }
总结复习
- scanf在遇到第一个空白就不再读取输入,其在读取输入时就会把空字符放在字符串末尾。