暑期dp46道(15)--HDU 1080 Human Gene Functions DFS+记忆化搜索

题目链接:HDOJ 1080



题意就是包含A、C、G、T的两个字符串a,b,可以在任意一个字符串任意位置加空格使得最终两个字符串要等长并且匹配的值要为最优解(两个空格匹配是不允许的)


思路:这题最终状态是两个字符串等长且匹配完成,那么我们可以认为这两个字符串的原串中的字符都完成匹配结束,因为空格匹配不允许,当原串中的字符匹配完成,自然就结束了

所以我们可以运用dfs的思想从两字符串当前下标开始按情况匹配,然后按照记忆化提高搜索效率。


实现细节:如果当前两字符串原串都没到结尾,当前有三种选择:

1.当前字符匹配搜索,两串下标都加1;

     2.串a当前字符和空格匹配,串b不匹配;

     3.反过来,串a不匹配,串b当前字符和空格匹配;

如果有一串到结尾,另一串和空格匹配直到结尾,返回0

如下:

int dfs(int x,int y)
{
    if(x>=len1&&y>=len2)
    return 0;
    int temp=dp[x][y];
    if(temp!=-300)//-300初始化用来记忆化搜索,因为此题匹配有负值的可能,所以要设的足够小
    {
        return temp;
    }
    int t=-1010;
    if(x<len1)
    {
        t=Max(t,dir[a[x]-1][4]+dfs(x+1,y));
        if(y<len2)
        {
            t=Max(t,Max(dir[a[x]-1][b[y]-1]+dfs(x+1,y+1),dir[b[y]-1][4]+dfs(x,y+1)));
        }
    }
    else
        t=Max(t,dir[b[y]-1][4]+dfs(x,y+1));
    return dp[x][y]=t;
}
代码:

#include<cstdio>  
#include<cstring>  
#include<string>  
#include<algorithm>  
using namespace std;  
#define Max(a,b) ((a>b)?a:b)  
#define M(a,b) memset(a,b,sizeof(a))  
#define Min(a,b) ((a<b)?a:b)  
#define debug 0  
#define REP(o) for(int i=0;i<o;i++)

const int maxn = 100+5;  
int a[maxn],b[maxn],len1,len2,dp[maxn][maxn];  
int dir[][5] = {{5,-1,-2,-1,-3},{-1,5,-3,-2,-4},{-2,-3,5,-2,-2},{-1,-2,-2,5,-1}};//数组记录匹配数值   

int dfs(int x,int y)  
{ 
    if(x >= len1 && y >= len2)//都达到结尾返回0   
        return 0;  
        
    int temp = dp[x][y];  
    if(temp != -300) //如果不是初始值说明这个点之后的最优解已经被搜索过了   
    {               //可以直接返回   
        return temp;  
    }  
    
    int t = -1010;   
    if(x < len1)  
    {  
        t = Max(t,dir[a[x] - 1][4] + dfs(x + 1,y));//a串匹配空格   
        if(y < len2)  
        {  
            t=Max(t,Max(dir[a[x] - 1][b[y] - 1]+dfs(x + 1,y + 1),dir[b[y] - 1][4] + dfs(x,y + 1)));//a,b匹配   
        }  
    }  
    else  
        t = Max(t,dir[b[y] - 1][4] + dfs(x,y + 1));//b串匹配空格   
    return dp[x][y] = t;//返回当前最优解   
}  
int main(){  
#if debug  
    freopen("in.txt","r",stdin);  
#endif //debug  
    int T;  
    scanf("%d",&T);  
    char t;  
    while(T--){  
          
        for(int i = 0;i < maxn;i++)  
            	for(int j = 0;j < maxn;j++)  
                		dp[i][j] = -300;//足够小  
                   
        scanf("%d",&len1);  
        for(int i = 0;i < len1;i++)  
        {  
            while((t = getchar()) == ' '||t == '\n');//转为整数值记录,便于数组的匹配   
            switch(t)  
            {  
                case 'A':a[i] = 1;  
                        break;  
                case 'C':a[i] = 2;  
                        break;  
                case 'G':a[i] = 3;  
                        break;  
                case 'T':a[i] = 4;  
                        break;  
                default:
						break;  
            }  
        }   
        scanf("%d",&len2);  
        for(int i  =0;i < len2;i++)  
        {  
            while((t = getchar()) == ' '||t == '\n');  
            switch(t)  
            {  
                case 'A':b[i] = 1;  
                        break;  
                case 'C':b[i] = 2;  
                		break;  
                case 'G':b[i] = 3;  
                		break;  
                case 'T':b[i] = 4;  
                		break;  
                default:
						break;  
            }  
        }  
          
        printf("%d\n",dfs(0,0));  
    }  
    return 0;  
}  
   



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值