POJ 3080 Blue Jeans

题目大意:

        基因地理工程是一个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, 资料组,数据集

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值