您的位置:首页 > 大数据 > 人工智能

hdu 2457 DNA repair (ac自动机+记忆化搜索)

2015-09-06 13:06 330 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2457

题意:给出N个DNA序列(只包含’A‘,'T','G','C'四种字符),然给一段DNA序列S,问最少改多少个字符使得这个DNA序列不包含前面任意一个DNA序列。



分析:将前面N个DNA序列建ac自动机,然后找出禁止走的位置。定义dp[i][j],i表示当前在字符串S的位置,j表示对应在ac机上的位置,dp[i][j]表示最小修改字符数。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int INF = 2e9+7;
const int maxn = 2015;
const int kd = 4;
int ncase;
struct trie
{
	int son[maxn][kd],fail[maxn],fbd[maxn];
	int cnt,root;
	
	int SL,ERROR,dp[maxn>>1][maxn>>1];
	char s[maxn];
	int newnode()
	{
		fill(son[cnt],son[cnt]+kd,-1);
		fbd[cnt]=0;
		return cnt++;
	}
	void Init()
	{
		cnt=0;
		root=newnode();
	}
	int idx(char ch)
	{
		switch(ch)
		{
			case 'A' : return 0;
			case 'C' : return 1;
			case 'G' : return 2;
			case 'T' : return 3;
		}
		return -1;
	}
	void Insert(char str[])
	{
		int now=root,i,index;
		for(i=0;str[i];i++)
		{
			index=idx(str[i]);
			if(son[now][index]==-1)
				son[now][index]=newnode();
			now=son[now][index];
		}
		fbd[now]=1;
	}
	void findfail()
	{
		queue <int> q;
		int i,temp;
		fail[root]=root;
		for(i=0;i<kd;i++)
			if(son[root][i]==-1)
				son[root][i]=root;
			else
			{
				fail[son[root][i]]=root;
				q.push(son[root][i]);
			}
		while(!q.empty())
		{
			temp=q.front();
			q.pop();
			fbd[temp]|=fbd[fail[temp]];
			for(i=0;i<kd;i++)
				if(son[temp][i]==-1)
					son[temp][i]=son[fail[temp]][i];
				else
				{
					fail[son[temp][i]]=son[fail[temp]][i];
					q.push(son[temp][i]);
				}
		}
	}
	int Next(int cur,int x)
	{
		if(fbd[cur] || fbd[son[cur][x]])
			return -1;
		return son[cur][x];
	}
	int DFS(int len,int cur)
	{
		if(len==SL)
			return 0;
		if(dp[len][cur]!=-1)
			return dp[len][cur];
		int ret[4]={INF,INF,INF,INF},index,temp;
		for(int i=0;i<kd;i++)
		{
			temp=Next(cur,i);
			if(temp!=-1)
			{
				index=idx(s[len]);
				if(index==i)
					ret[i]=DFS(len+1,temp);
				else
					ret[i]=DFS(len+1,temp)+1;
			}
		}
		for(int i=1;i<kd;i++)
			if(ret[i]<ret[0])
				ret[0]=ret[i];
		return dp[len][cur]=ret[0];
	}
	void solve()
	{
		SL=strlen(s);
		memset(dp,-1,sizeof(dp));
		int ans=DFS(0,root);
		if(ans>=INF)
			printf("Case %d: %d\n",ncase++,-1);
		else
			printf("Case %d: %d\n",ncase++,ans);
	}
}ac;

int main()
{
	int n,i,j;
	ncase=1;
	while(scanf("%d",&n)!=EOF&&n)
	{
		ac.Init();
		while(n--)
		{
			scanf("%s",ac.s);
			ac.Insert(ac.s);
		}
		ac.findfail();
		scanf("%s",ac.s);
		ac.solve();
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: