/* 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:
有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?
已经告诉你了,这是个DP的题目,你能AC吗?
输入
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
输出
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
样例输入
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出
30
*/
/************************************************************************/
#include "stdafx.h"
/* 数塔问题:已经描述过(常用算法-动态规划) */
/************************************************************************/
#include "stdafx.h"
int GestMaxSumFromeShuTa(int pArray[][5],int levelNum)
{
int resutlt = 0;
int** sumArray = new int*[levelNum];
for(int i=0;i<levelNum;i++)
sumArray[i] = new int[levelNum];
for(int i=0;i<levelNum;i++)
sumArray[levelNum-1][i] = pArray[levelNum-1][i];
for(int i=levelNum-2;i>=0;i--)
for(int j=0;j<=i;j++)
{
sumArray[i][j] = max(pArray[i][j]+sumArray[i+1][j],pArray[i][j]+sumArray[i+1][j+1]);
printf("(%d,%d),%d\n",i,j,sumArray[i][j]);
}
resutlt = sumArray[0][0];
for(int i=0;i<levelNum;i++)
delete[] sumArray[i];
delete[] sumArray;
return resutlt;
}
void TestShuta()
{
int Ta[5][5] = {{7},
{3,8},
{8,1,0},
{2,7,4,4},
{4,5,2,6,5}};
printf("%d\n",GestMaxSumFromeShuTa(Ta,5));
}
2:装配线调度/************************************************************************/
/* 装配线调度问题:算法导论 P193 */
/************************************************************************/
#include "stdafx.h"
#include <memory.h>
void BestSchedu(int* s1,int* s2,int len,int* t1,int* t2,int e1,int e2,int x1,int x2,int* resultArray,int& resultValue)
{
/*s1装配线1在各个装配站的耗时,len装配站个数,t1又装配站1到装配站2耗时只能从装配站的j-1站到转配线2的j站,e1进入装配站
1的时间,x1离开装配站1的时间,resultArray 线路数组,resultvalue返回最小耗时
*/
int* f1 = new int[len];
memset(f1,0,sizeof(int)*len);
int* f2 = new int[len];
memset(f2,0,sizeof(int)*len);
int* path1 = new int[len];
memset(path1,0,sizeof(int)*len);
int* path2 = new int[len];
memset(path2,0,sizeof(int)*len);
int lastStep = 0;
f1[0] = *s1+e1;
f2[0] = *s2+e2;
for(int j=1;j<len;j++)
{
if(f1[j-1]<f2[j-1]+t2[j-1])
{
f1[j] = f1[j-1]+*(s1+j);
path1[j] = 1;
}
else
{
f1[j] = f2[j-1]+t2[j-1]+*(s1+j);
path1[j] = 2;
}
if(f2[j-1]<f1[j-1]+t1[j-1])
{
path2[j] = 2;
f2[j] = f2[j-1]+*(s2+j);
}
else
{
f2[j] = f1[j-1]+t1[j-1]+*(s2+j);
path2[j] = 1;
}
}
if(f1[len-1]+x1<f2[len-1]+x2)
{
resultValue = f1[len-1]+x1;
lastStep =1;
}
else
{
resultValue = f2[len-1]+x2;
lastStep = 2;
}
resultArray[len -1] = lastStep;
for(int j=len-2;j>=0;j--)
{
if(lastStep==1)
resultArray[j] = path1[j+1];
else
resultArray[j] = path2[j+1];
lastStep = resultArray[j];
}
delete f1;
delete f2;
delete path1;
delete path2;
}
void TestBestSchedu()
{
int s1[] = {7,9,3,4,8,4};
int s2[] = {8,5,6,4,5,7};
int t1[] = {2,3,1,3,4};
int t2[] = {2,1,2,2,1};
int e1 =2,e2 = 4;
int x1 = 3,x2 = 2;
int* resultArray = new int[6];
int resultValue = 0;
BestSchedu(s1,s2,6,t1,t2,e1,e2,x1,x2,resultArray,resultValue);
printf("%d\n",resultValue);
delete resultArray;
}
3:矩阵乘法链
/************************************************************************/
/* 矩阵乘法链:算法导论P198
A:pxq B:qxr
A*B 所用乘法次数为p*q*r
目的:求解一组加权括号使矩阵乘法链的结果所用乘法次数最少
最优子结构:m[i,j]为从矩阵AiAi+1....Aj加权括号
重叠子问题:m[i,j] = min{m[i,k]+m[k+1,j]+pi-1*pk*pj}*/
/************************************************************************/
#include "stdafx.h"
#include <memory.h>
int matrixchain(int* pArray,int** s,int len)
{
int result=0;
int** mArray = new int*[len+1];
for(int i=0;i<=len;i++)
{
mArray[i] = new int[len+1];
memset(mArray[i],0,sizeof(int)*(len+1));
}
for(int i=1;i<=len;i++)
mArray[i][i] = 0;
for(int k=1;k<=len;k++)
for(int i=1;i<=len-k;i++)
{
int j= i+k;
mArray[i][j] = 100000;
for(int m=i;m<j;m++)
{
int temp = mArray[i][m]+mArray[m+1][j]+pArray[i-1]*pArray[m]*pArray[j];
if(temp<mArray[i][j])
{
mArray[i][j] = temp;
s[i][j] = m;
}
}
}
result = mArray[1][len];
for(int i=0;i<=len;i++)
{
delete[] mArray[i];
mArray[i] = NULL;
}
delete mArray;
mArray = NULL;
return result;
}
void printResult(int** s,int i,int j)
{
if(i==j)
printf("A%d",i);
else
{
printf("(");
printResult(s,i,s[i][j]);
printResult(s,s[i][j]+1,j);
printf(")");
}
}
void Testmatrixchain()
{
int data[] = {30,35,15,5,10,20,25};
int len =6;
int** s;
s= new int*[len+1];
for(int i=0;i<len+1;i++)
s[i] = new int[len+1];
printf("%d\n",matrixchain(data,s,6));
printResult(s,1,6);
for(int i=0;i<len+1;i++)
delete[] s[i];
delete s;
}
4:求解最长公共字串
/************************************************************************/
/* 求解最长公共子序列:LCS 算法导论:p208
最优子结构:c[i,j]表示
字符串x; x1x2x3x4....xi
字符串y: y1y2y3y4....yj
最长公共字串的长度
重叠子问题:
c[i,j] = c[i-1,j-1] x[i]==y[j];
c[i,j] = max(c[i-1,j],c[i,j-1]) x[i]\=y[j];
*/
/************************************************************************/
#include "stdafx.h"
int Lcs(char* pSrcA,int lenA,char* pSrcB,int lenB,int** pRecordArray,char** recordDir)
{
//int result = 0;
for(int i=0;i<=lenB;i++)
{
pRecordArray[0][i] = 0;
recordDir[0][i] = '0';
}
for(int j=0;j<=lenA;j++)
{
pRecordArray[j][0] = 0;
recordDir[j][0] = '0';
}
for(int i=1;i<=lenA;i++)
for(int j=1;j<=lenB;j++)
{
if(pSrcA[i-1]==pSrcB[j-1])
{
pRecordArray[i][j] = pRecordArray[i-1][j-1]+1;
recordDir[i][j] = 'p';
}
else
{
if(pRecordArray[i-1][j]>pRecordArray[i][j-1])
{
pRecordArray[i][j] = pRecordArray[i-1][j];
recordDir[i][j] = 'q';
}
else
{
pRecordArray[i][j] = pRecordArray[i][j-1];
recordDir[i][j] = 'r';
}
}
}
return pRecordArray[lenA][lenB];
}
void printLcs(char* pSrcA,char* pSrcB,char** recordDir,int i,int j)
{
if(i<0||j<0)
return;
if(recordDir[i][j]=='p')
{
printf("%c",pSrcA[i-1]);
printLcs(pSrcA,pSrcB,recordDir,i-1,j-1);
}
else if(recordDir[i][j]=='q')
printLcs(pSrcA,pSrcB,recordDir,i-1,j);
else
printLcs(pSrcA,pSrcB,recordDir,i,j-1);
}
void testLcs()
{
int lenA = 8;
int lenB = 7;
char x[]={'A','B','C','B','D','A','B','E'};
char y[]={'B','D','C','A','B','A','E'};
//int result[9][8];
//char record[9][8];
int** result = new int*[lenA+1];
for(int i=0;i<=lenA;i++)
result[i] = new int[lenB+1];
char** record = new char*[lenA+1];
for(int i=0;i<=lenA;i++)
record[i] = new char[lenB+1];
printf("%d\n", Lcs(x,8,y,7,result,record));
for(int i=0;i<=lenA;i++)
{
for(int j=0;j<=lenB;j++)
printf("%c ",record[i][j]);
printf("\n");
}
printLcs(x,y,record,lenA,lenB);
for(int i=0;i<=lenA;i++)
delete[] record[i];
delete[] record;
for(int i=0;i<=lenA;i++)
delete[] result[i];
delete[] result;
}
/************************************************************************/
5:求解所有点对最短路径 动态规划+BFS
/* 动态规划求解所有节点最短路径对 ,时间复杂性为0(n.^3),Dijkstra算法求解的是单源最短路径
时间复杂性为0(n.^2)*/
/************************************************************************/
#include "stdafx.h"
void printPath(int keyArray[][6],int num,int i,int j)
{
if(i==j)
return;
if(keyArray[i][j]==0)
printf("%d ",j);
else
{
printPath(keyArray,num,i,keyArray[i][j]);
printPath(keyArray,num,keyArray[i][j],j);
}
}
void GetAllPointShortestPath(int pAdj[][6],int num,int recordArray[][6],int keyArray[][6])
{
for(int i=1;i<=num;i++)
for(int j=1;j<=num;j++)
{
recordArray[i][j] = pAdj[i][j];
keyArray[i][j]= 0;
}
//for(int i=1;i<=num;i++)
// recordArray[i][i] = 0;
for(int i=1;i<=num;i++)
for(int j=1;j<=num;j++)
for(int k=1;k<=num;k++)
{
if(recordArray[i][k]!=-1&&recordArray[k][j]!=-1&&(recordArray[i][j]==-1||
recordArray[i][j]>recordArray[i][k]+recordArray[k][j]))
{
recordArray[i][j] = recordArray[i][k]+recordArray[k][j];
keyArray[i][j] = k;
}
}
/*for(int i=1;i<=num;i++)
for(int j=1;j<=num;j++)
printf("%d ",keyArray[i][j]);*/
for(int i=1;i<=num;i++)
for(int j=1;j<=num;j++)
{
/*if(recordArray[i][j]>0)
{
printf("from %d to %d:shortest path is %d\n",i,j,recordArray[i][j]);
printf("the path is: \n");
printPath(keyArray,num,i,j);
printf("\n");
}*/
if(recordArray[i][j]==-1)
printf("there is no way from %d to %d\n",i,j);
else
{
printf("the path from %d to %d is:%d\n",i,j,recordArray[i][j]);
printf("%d ",i);
printPath(keyArray,num,i,j);
printf("\n");
}
}
}
void testShortestPath()
{
int array[6][6]={{0,0,0,0,0,0},
{0,-1,4,2,-1,8},
{0,-1,-1,-1,4,5},
{0,-1,-1,-1,1,-1},
{0,-1,-1,-1,-1,3},
{0,-1,-1,-1,-1,-1}};
int cost[6][6];
int key[6][6];
GetAllPointShortestPath(array,5,cost,key);
}
6:求解最长递增子序列
#include "stdafx.h"
/************************************************************************/
/* 求解最长递增子序列 */
/************************************************************************/
int FindPosition(int dst,int* s,int s_len)
{
for(int i=1;i<=s_len;i++)
if(s[i]>dst)
return i;
return s_len+1;
}
int FindPosition_binary(int dst,int* s,int s_len)
{
int low=1,high = s_len,mid = 0;
//bool find = false;
while(low<=high)
{
mid = (low+high)/2;
if(s[mid]>=dst)
high = mid - 1;
else
low = mid +1 ;
}
if(s[mid]<dst)
return mid + 1;
else
return mid;
}
int longestIncreaseSub(int* pSrc,int len)
{
int result = 0,s_len = 0;
int* tempSub = new int[len];
int* s = new int[len+1];
tempSub[0] = 1;
s[1] = pSrc[0];
s_len = 1;
result = 1;
for(int i=1;i<len;i++)
{
int iPosition = FindPosition_binary(pSrc[i],s,s_len);
if(iPosition>s_len)
{
s[iPosition] = pSrc[i];
s_len++;
}
else
s[iPosition] = pSrc[i];
tempSub[i] = iPosition;
if(tempSub[i]>result)
result = tempSub[i];
}
for(int i=0;i<len;i++)
printf("%d ",tempSub[i]);
printf("\n");
for(int i=1;i<=s_len;i++)
printf("%d ",s[i]);
printf("\n");
delete[] s;
delete[] tempSub;
return result;
}
void testLongestIncreaseSub()
{
int a[]={1,3,4,2,7,8,6,3,4,5,6,7};
printf("%d\n",longestIncreaseSub(a,12));
}
7:最大子段求和
/************************************************************************/
/* 给定由n个整数(可能为负整数)组成的序列a1,a2,...,an,给出动态规划算法求该序列形如(ai+...+aj)
的子段的和的最大值(1<=i<=j<=n),并说明算法的时间复杂度和空间复杂度。当所有整数都为负整数时定义其最大字段和为0.
依此定义,所求的最优值为max(0,max(ai+...+aj))(1<=i<=j<=n)。例如,当(a1,a2,a3,a4,a5,a6)=(-2,11,-4,13,-5,-2)时,
最大子段和为(a2+a3+a4)=20 */
/************************************************************************/
/************************************************************************/
/* 最大子段字段和问题:已练习过(常用算法-动态规划) */
/************************************************************************/
#include "stdafx.h"
int SubSumMax(int* pArray,int len)
{
int* tempArray = new int[len];
int max=tempArray[0] = pArray[0];
for(int i=1;i<len;i++)
{
if(tempArray[i-1]<0)
tempArray[i] = pArray[i];
else
tempArray[i] = pArray[i]+tempArray[i-1];
if(tempArray[i]>max)
max = tempArray[i];
}
delete[] tempArray;
return max;
}
void testSubSumMax()
{
int testData[] = {7,3,-17,9,3,34,-5,10};
printf("%d\n",SubSumMax(testData,8));
}