您的位置:首页 > 编程语言 > C语言/C++

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

2016-08-09 14:17 686 查看
题目链接: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
4000
) 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息