题目大意:
基因地理工程是一个IBM和国家地理学会合作的项目,该项目意在绘制出基因地图以考察地球上的基因分布以及人口变动等信息,作为IBM研究员你的任务是写一段程序从给定的若干DNA序列中寻找共性。
现有多个测例(测例数题中给出),每个测例都会给出基因数m(2 ≤ m ≤ 10),每条基因长度都是60,都由ATCG四种字母组成,对于每个测例都打印出各个基因都包含的一条最长的公共子序列,如果有多条长度相同的答案,输出字典序最小的一条。
注释代码:
/*
* Problem ID : POJ 3080 Blue Jeans
* Author : Lirx.t.Una
* Language : GCC
* Run Time : 0 ms
* Run Memory : 368 KB
*/
#pragma GCC optimize("O2")
#include <string.h>
#include <stdio.h>
//既然是找m条基因段中的最长公共子序列
//既然是公共的,则该片段必然出现在每条基因中
//因此可以在第一条基因上枚举所长度的片段
//然后拿这些片段和其余每条基因进行KMP匹配
//选出能匹配所有基因的最长公共子序列即可
#define TRUE 1
#define FALSE 0
//length of gene base
//基因序列的长度
#define LEN 60
//maximum number of gene bases
//基因的最大条数
//下标从1开始
#define MAXGEN 11
//每条基因的KMP长度
#define GELEN 62
typedef int BOOL;
char ge[MAXGEN][GELEN];//gene,存放每条基因的信息
char nxt[GELEN];//next数组
char mod[GELEN];//mode string,模式串
char ans[GELEN];//存放最终结果
void
bd_nxt( char *s, int len ) {
int i, j;
nxt[1] = 0;
for ( j = 0, i = 2; i <= len; i++ ) {
while ( j > 0 && s[j + 1] != s[i] )
j = nxt[j];
if ( s[j + 1] == s[i] )
j++;
nxt[i] = j;
}
}
BOOL
kmp( char *p, char *m, int plen, int mlen ) {
//KMP匹配,匹配成功就返回TRUE
//prime string,modestring,length of prime string,length of mode string
//主串,模式串,主串长,模式串长
int i, j;
for ( j = 0, i = 1; i <= plen; i++ ) {
while ( j > 0 && m[j + 1] != p[i] )
j = nxt[j];
if ( m[j + 1] == p[i] )
j++;
if ( j == mlen )
return TRUE;
}
return FALSE;
}
BOOL
chk( char *m, int mlen, int n ) {//check
//拿模式串去和2~n号基因进行匹配
//如果匹配成功则返回TRUE
//只要有一个基因不能和m匹配则失败FALSE
//当然该模式串一定存在于1号基因中,
//因为该模式串就是取自1号基因的
//mlen为length of mode string
int i;
bd_nxt( m, mlen );//先对该模式串构造next数组
for ( i = 2; i <= n; i++ )
if ( !kmp( ge[i], m, LEN, mlen ) )
return FALSE;
return TRUE;
}
int
main() {
int t;//测例数
int n;//共有多少基因序列
int ml;//length of mode string,模式串长
int al;//length of answer string,答案串长
int i;//计数变量
scanf("%d", &t);
while ( t-- ) {
scanf("%d", &n);
for ( i = 1; i <= n; i++ )
scanf("%s", ge[i] + 1);
//枚举1号基因上所有长度的片段(子序列)
//长度从1涨到LEN,以从左向右滑动的方式进行枚举
for ( al = 0, ml = 1; ml <= LEN; ml++ ) {//枚举长度
//注意!strncpy并不会在最后一个字符后面自动加上'\0'
//因此需要自己手动添加该空字符
mod[ml + 1] = '\0';
for ( i = 1; i <= LEN - ml + 1; i++ ) {//利用该长度在ge[i]+1串上滑动
strncpy(mod + 1, ge[1] + i, ml);//取模式串
if ( chk( mod, ml, n ) )//检查mod和其余基因间的匹配关系
//过了上句就表示能匹配
if ( ml > al ) {
al = ml;
strcpy(ans, mod + 1);
}
else
if ( ml == al && strcmp(mod + 1, ans) < 0 )//若相等字典序小的靠前
strcpy(ans, mod + 1);
}
}
if ( al < 3 )//按照题意,长度小于3就输出失败信息
puts("no significant commonalities");
else
puts(ans);
}
return 0;
}
无注释代码:
#pragma GCC optimize("O2")
#include <string.h>
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define LEN 60
#define MAXGEN 11
#define GELEN 62
typedef int BOOL;
char ge[MAXGEN][GELEN];
char nxt[GELEN];
char mod[GELEN];
char ans[GELEN];
void
bd_nxt( char *s, int len ) {
int i, j;
nxt[1] = 0;
for ( j = 0, i = 2; i <= len; i++ ) {
while ( j > 0 && s[j + 1] != s[i] )
j = nxt[j];
if ( s[j + 1] == s[i] )
j++;
nxt[i] = j;
}
}
BOOL
kmp( char *p, char *m, int plen, int mlen ) {
int i, j;
for ( j = 0, i = 1; i <= plen; i++ ) {
while ( j > 0 && m[j + 1] != p[i] )
j = nxt[j];
if ( m[j + 1] == p[i] )
j++;
if ( j == mlen )
return TRUE;
}
return FALSE;
}
BOOL
chk( char *m, int mlen, int n ) {
int i;
bd_nxt( m, mlen );
for ( i = 2; i <= n; i++ )
if ( !kmp( ge[i], m, LEN, mlen ) )
return FALSE;
return TRUE;
}
int
main() {
int t;
int n;
int ml;
int al;
int i;
scanf("%d", &t);
while ( t-- ) {
scanf("%d", &n);
for ( i = 1; i <= n; i++ )
scanf("%s", ge[i] + 1);
for ( al = 0, ml = 1; ml <= LEN; ml++ ) {
mod[ml + 1] = '\0';
for ( i = 1; i <= LEN - ml + 1; i++ ) {
strncpy(mod + 1, ge[1] + i, ml);
if ( chk( mod, ml, n ) )
if ( ml > al ) {
al = ml;
strcpy(ans, mod + 1);
}
else
if ( ml == al && strcmp(mod + 1, ans) < 0 )
strcpy(ans, mod + 1);
}
}
if ( al < 3 )
puts("no significant commonalities");
else
puts(ans);
}
return 0;
}
模式串从大到小枚举更加优化:
/*
* Problem ID : POJ 3080 Blue Jeans
* Author : Lirx.t.Una
* Language : C
* Run Time : 0 ms
* Run Memory : 128 KB
*/
#include <string.h>
#include <stdio.h>
#define MAXN 10
#define MAXM 60
char g[MAXN][MAXM + 1];
char m[MAXM + 1];
char ans[MAXM + 1];
char prv[MAXM];
int n;
void
build(int ml) {
int i, j;
prv[0] = -1;
for ( j = -1, i = 1; i < ml; i++ ) {
while ( j > -1 && m[j + 1] != m[i] ) j = prv[j];
if ( m[j + 1] == m[i] ) j++;
prv[i] = j;
}
}
int
kmp( int ml, int tl, char *t ) {
int i, j;
for ( j = -1, i = 0; i < tl; i++ ) {
while ( j > -1 && m[j + 1] != t[i] ) j = prv[j];
if ( m[j + 1] == t[i] ) j++;
if ( j + 1 == ml ) return 1;
}
return 0;
}
int
check( int ml, int tl ) {
int i;
build(ml);
for ( i = 1; i < n; i++ )
if ( !kmp( ml, tl, g[i] ) )
return 0;
return 1;
}
int
main() {
int tst;
int i;
int ml, tl;
int al;
tl = MAXM;
scanf("%d", &tst);
while ( tst-- ) {
scanf("%d", &n);
for ( i = 0; i < n; i++ ) scanf("%s", g[i]);
al = 0;
for ( ml = tl; ml > 0 && ml >= al; ml-- ) {
for ( i = 0; i + ml <= tl; i++ ) {
strncpy(m, g[0] + i, ml);
m[ml] = '\0';
if ( check( ml, tl ) )
if ( ml > al ) {
al = ml;
strcpy(ans, m);
}
else if ( strcmp(m, ans) < 0 )
strcpy(ans, m);
}
}
if ( al < 3 ) puts("no significant commonalities");
else puts(ans);
}
return 0;
}
单词解释:
The Genographic Project:基因地理工程,一个IBM公司参与的基因的地理分布图工程,以研究世界人口如何演变和迁移
partenership:n, 合作关系
The National Geographic Society:国家地理学会
contributor:n, 捐助者,贡献者
populate:vt, 居住于,构成人口
map:vt, 绘制地图
researcher:n, 研究员
task:vt, 分派任务
commonality:n, 共性,公共
amongst:prep, 在...之中
snippet:n, 小片,片段
correlate:vt, 相互有关系
survey:n, 调查,测量
genetic:adj, 基因的,遗传的
nitrogen:n, 氮
note:vt, 标记,注解
molecule:n, 分子,微粒
adenine:n, 腺嘌呤
thymine:n, 胸腺嘌呤
guanine:n, 鸟嘌呤
cytosine:n, 胞嘧啶
jeans:n, 牛仔裤,工装裤
dataset:n, 资料组,数据集