HDU-2457 DNA repair【AC自动机+DP】

第一次。。自己分析出来的dp。。。。。
和之前做过的题很像,感觉有关构造字符串的题都有套路。
dp中一定包含一维trie图中的节点状态(好像是废话)
这道题我们用dp[i][j]表示长度为i节点状态为j最少消去的数量。
状态转移就是dp[i][u] = min(dp[i][u], dp[i-1][j]+(ch!=ss[i]));

#include<bits/stdc++.h>
using namespace std;
int T = 0;
int Hash(char ch) {
	if(ch == 'A') return 0;
	else if(ch == 'T') return 1;
	else if(ch == 'G') return 2;
	else if(ch == 'C') return 3;
	else return -1;
}
struct AC{
	int nex[1005][4], root, tot;
	int f[1005], ed[1005];
	int newnode() {
		for(int i = 0; i < 4; i++) nex[tot][i] = -1;
		ed[tot] = 0;
		return tot++;
	}
	void init() {
		tot = 0;
		root = newnode();
	}
	void insert(char *s) {
		int u = root, len = strlen(s);
		for(int i = 0; i < len; i++) {
			int ch = Hash(s[i]);
		if(nex[u][ch] == -1) nex[u][ch] = newnode();
			u = nex[u][ch];
		}
		ed[u] = 1;
	}
	void getfail() {
		queue<int>Q;
		for(int i = 0; i < 4; i++) {
			if(nex[root][i] == -1) nex[root][i] = root;
			else {
				f[nex[root][i]] = root;
				Q.push(nex[root][i]);
			}
		}
		while(!Q.empty()) {
			int u = Q.front();Q.pop();
			ed[u] |= ed[f[u]];
			for(int i = 0; i < 4; i++) {
				if(nex[u][i] == -1) nex[u][i] = nex[f[u]][i];
				else {
					f[nex[u][i]] = nex[f[u]][i];
					Q.push(nex[u][i]);
				}
			}
		}
	}
}ac;
char ss[1005];
int dp[1005][1005];
int main() {
	int n;
	while(scanf("%d", &n) == 1 && n) {
		ac.init();
		for(int i = 0; i < n; i++) {
			scanf("%s", ss);
			ac.insert(ss);
		}
		ac.getfail();
		scanf("%s", ss);
		int len = strlen(ss);
		memset(dp, 0x3f3f3f3f, sizeof(dp));
		dp[0][0] = 0;
		for(int i = 1; i <= len; i++) {
			int ch = Hash(ss[i-1]);
			for(int s = 0; s < ac.tot; s++) {
				if(ac.ed[s] || dp[i-1][s] == 0x3f3f3f3f) continue;
				for(int c = 0; c < 4; c++) {
					int u = ac.nex[s][c];
					if(ac.ed[u]) continue;
					if(ch == c) {
						dp[i][u] = min(dp[i][u], dp[i-1][s]);
					}
					else dp[i][u] = min(dp[i][u], dp[i-1][s]+1);
				}
			}
		}
		int res = 0x3f3f3f3f;
		for(int s = 0; s < ac.tot; s++)
			res = min(res, dp[len][s]);
		printf("Case %d: %d\n", ++T, (res==0x3f3f3f3f)?-1:res);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值