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;
}

 

posted @ 2015-08-06 16:35  Scale_the_heights  阅读(158)  评论(0)    收藏  举报