您的位置:首页 > 其它

动态规划基础问题

2013-09-18 17:39 357 查看
#include <iostream>
using namespace std;

int b[10][10];
int c[10][10];
//最大连续子串问题
//比如{5,-3,4,2}的最大子序列就是 {5,-3,4,2},它的和是8,达到最大;
//而 {5,-6,4,2}的最大子序列是{4,2},它的和是6。
//你已经看出来了,找最大子序列的方法很简单,只要前i项的和还没有小于0那么子序列就一直向后扩展,否则丢弃之前的子序列开始新的子序列,
//同时我们要记下各个子序列的和,最后找到和最大的子序列。

void maxlianxuSub(int* src,int length)
{
int flag=0;
int currentSum=0;
int maxSum=0;
int strStart=0;
int strEnd=0;
for (int i=0;i<length;i++)
{
if (currentSum<=0)
{
strStart=i;
currentSum=src[i];
}
else
{
currentSum=currentSum+src[i];
}

if (currentSum>maxSum)
{
strEnd=i;
maxSum=currentSum;
}
}
cout<<"最大和为:"<<maxSum<<endl;
cout<<"序列为:"<<endl;
for (int j=strStart;j<=strEnd;j++)
{
cout<<src[j]<<" ";
}
}

//最长递增子序列 比如arr={1,5,8,2,3,4}的最长递增子序列是1,2,3,4

//方法一:DP

//像LCS一样,从后向前分析,很容易想到,第i个元素之前的最长递增子序列的长度要么是1(单独成一个序列),要么就是第i-1个元素之前的最长递增子序列加1,可以有状态方程:

//LIS[i] = max{1,LIS[k]+1},其中,对于任意的k<=i-1,arr[i] > arr[k],这样arr[i]才能在arr[k]的基础上构成一个新的递增子序列。

//代码如下:在计算好LIS长度之后,output函数递归输出其中的一个最长递增子序列。

int dp[100];//保存数据的lis值
int lis;//最大lis值

int longestIncreseSequence(int* src,int len)
{
if (src==NULL||len<0)
{
return -1;
}
dp[0]=1;
for (int i=0;i<len;i++)
{
for (int j=0;j<i;j++)
{
if (src[i]>src[j]&&dp[i]<dp[j]+1)
{
dp[i]=dp[j]+1;
}
}
if (dp[i]>lis)
{
lis=dp[i];
}
}
return lis;
}

void outputLis(int* src,int index)
{
bool isLis=false;
if (src==NULL||index<=0)
{
return;
}
if (dp[index]==lis)
{
--lis;
isLis=true;
}
outputLis(src,--index);
if (isLis)
{
cout<<src[index+1]<<" ";
}
}

//最长公共子串(连续)
//例如 str1="234543" str2="32234"
//采用DP的思想,如果str1[i] = str2[j],那么此处的包含str1[i] 和 str2[j]公共子串的长度必然是包含str1[i-1]和str2[j-1]的公共子串的长度加1,那么现在我们可以重新定义lcs(i,j),
//即是lcs(i,j) = lcs(i-1,j-1) + 1,反之,lcs(i,j) = 0。那么上面的矩阵就变成了如下的样子:

//--b a b

//c 0 0 0

//a 0 1 0

//b 1 0 2

//a 0 2 0
//
//现在问题又变简单了,只需要花n^2的时间构造这样一个矩阵,再花n^2的时间去找到矩阵中最大的那个值,对应的就是最长公共子串的长度,而最大值对应的位置对应的字符,就是最长公共子串的最末字符。

//算法还可以改进,我们可以将查找最大长度和对应字符的工作放在构造矩阵的过程中完成,
//一边构造一边记录当前的最大长度和对应位置,这样就节省了n^2的查找时间。

//空间上也可以做改进,如果按照如上的方式构造,我们发现,当矩阵的第i+1行的值计算完成后,
//第i行的值就没有用了,即便是最长的长度出现在第i行,我们也已经用变量记录下来了。因此,可以将矩阵缩减成一个向量来处理,向量的当前值对应第i行,向量的下一个循环后的值对应第i+1行。

void LCSlianxu(char* str1,char*str2)
{
int length1=strlen(str1);
int length2=strlen(str2);
int *result=new int[length2+1];
memset(result,0,(length2+1)*4);
int max_len=0;
int pos=0;
for (int i=0;i<length1;i++)
{
for(int j=length2;j>=0;j--)
{
if (str1[i]==str2[j-1])
{
result[j]=result[j-1]+1;
if (result[j]>max_len)
{
max_len=result[j];
pos=j-1;
}

}
else
{
result[j]=0;
}
}
}

for (int k=pos-max_len+1;k<=pos;k++)
{
cout<<str2[k]<<" ";
}
}

//最长公共子序列不连续
//引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向。
//我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。

//算法分析:
//由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m + n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m + n)。

void LCSLength(char* src1,int m,char* src2,int n,int c[][10],int b[][10])
{

for (int i=0;i<=m;i++)
{
c[i][0]=0;
}
for(int j=1;j<n;j++)
{
c[0][j]=0;
}
for (int i=1;i<=m;i++)
{
for (int j=1;j<=n;j++)
{
if (src1[i-1]==src2[j-1])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=0;
}
else if (c[i-1][j]>c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=1;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=-1;
}
}
}
}

void printLCS(int b[][10],char* src1,int i,int j)
{
if (i==0||j==0)
{
return;
}
if (b[i][j]==0)
{
printLCS(b,src1,i-1,j-1);
cout<<src1[i-1]<<" ";
}
if (b[i][j]==1)
{
printLCS(b,src1,i,j-1);
}
if (b[i][j]==-1)
{
printLCS(b,src1,i-1,j);
}
}
int main()
{
char str1[]="34123523452345";
char str2[]="2341234134";
LCSLength(str1,strlen(str1),str2,strlen(str2),c,b);
printLCS(b,str1,strlen(str1),strlen(str2));
// LCSlianxu(str1,str2);
//cout<<longestIncreseSequence(src,sizeof(src)/4);
//outputLis(src,sizeof(src)/4-1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: