hdu 1560 IDA* 算法
题意:输入n个字符串(只包括ACGT4种字母),现在要求一个最短的字符串,使得输入的n字符串都是这个字符串的子序列,求这个最短的长度是多少。
解法:只有4种字母,且n<=8 ,每个字符串的长度不超过5,因此目标串的最大长度不超过8*5 = 40,如果暴力dfs那么有可能要搜索(4^40) 次显然不行,所以要剪枝。而且我们要求得是最短目标串的长度,所以用迭代加深搜索的方法,枚举每次dfs的层数。
剪枝策略:可以求出当前还需要字母'A'、'C'、'G'、'T'的个数,他们的和为sum, 如果剩余的递归次数 < sum ,显然是不能得到符合要求的串,所以不用再走下去了
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; char str[10][10] ; int num[10][10] , len1[10] , ch[500] , n; int Max(int *temp) { int maxn[10] ; memset(maxn,0,sizeof maxn) ; for(int i=0;i<n;i++){ int ret[10]; memset(ret, 0 ,sizeof(ret)); for(int j=temp[i];j<len1[i];j++){ ret[num[i][j]]++; } for(int k=1;k<=4 ;k++){ maxn[k]=max(maxn[k],ret[k]); } } return maxn[1]+maxn[2]+maxn[3]+maxn[4] ; } int dfs(int dep ,int *temp){ int tt[10] ; if(Max(temp)>dep) return 0; if(dep == 0) return 1; for(int i=1;i<=4 ; i++){ for(int j=0;j<n;j++){ if(temp[j]<len1[j] && num[j][temp[j]] == i){ tt[j]=temp[j]+1 ; } else{ tt[j] = temp[j]; } } if(dfs(dep-1 , tt )) return 1; } return 0; } void solve() { int dep=0; int temp[10] ; memset(temp,0,sizeof temp); while(!dfs(dep,temp)){ //cout<<dep<<endl; dep++; } printf("%d\n",dep) ; } int main() { ch['A']=1,ch['C']=2,ch['G']=3,ch['T']=4; int t; scanf("%d",&t); while(t--){ scanf("%d",&n) ; getchar() ; for(int i=0; i<n;i++){ gets(str[i]) ; } for(int i=0;i<n;i++){ int len=strlen(str[i]) ; len1[i] = len; for(int j=0;j<len;j++){ num[i][j] = ch[str[i][j]] ; } } solve() ; } return 0; }

浙公网安备 33010602011771号