算法(一)

动态规划

一、递归

#include<iostream>
#include<string>
using namespace std;

int n; 
int Hanoi(int n)
{
	if(n==1)
	{
		return 1;
	}
	else
	{
	  return  2*Hanoi(n-1)+1;
	}
}
int main()
{
	int n=3;
	cout<<Hanoi(n); 
}

 

 2、递推

#include<iostream>
#include<string>
using namespace std;
const int Max=64;
int h[Max]={0};
int main()
{
	int n;
	cin>>n;
	h[1]=1;
	for(int i=2;i<=n;i++)
	{
		h[i]=h[i-1]*2+1;
	}
	cout<<h[n]<<endl;
}

 

二、 

1、二维数组的定义

#include<iostream>
#include<algorithm>
#define Max 101
using namespace std;
int D[Max][Max];
int n;
//int MaxSum(int i,int j)

int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<=i;j++)
		    cin>>D[i][j];
	}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<=i;j++)
		    cout<<D[i][j]<<" ";
		cout<<endl;
	}
	
}

2、

#include<iostream>
#include<algorithm>
#define Max 101
using namespace std;
int D[Max][Max];//输入初始矩阵图 
int n;//全局变量 
int s=0;
int MaxSum(int i,int j)//i,j 到底部的最大距离
{
	if(i==n)//边界条件,到底部时,等于本身
	{
		return D[i][j];
	} 
	else
	{
		return D[i][j]+max(MaxSum(i+1,j),MaxSum(i+1,j+1));//返回位置到底部的最大距离,自己值,加上次求解的最大值。
	}
} 

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		    cin>>D[i][j];
	}
	cout<<endl;
	cout<<MaxSum(1,1);
	//5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
}

因为是三角形,所有情况就都会通过递归搜索得到。

3、

 

#include<iostream>
#include<algorithm>
#define MAX 101

using namespace std;
int D[MAX][MAX];//输入初始矩阵图 
int n;//全局变量 
int s=0;
int maxSum[MAX][MAX];

int MaxSum(int i,int j) //i,j位置的数到最底层的最大距离 
{
	if(maxSum[i][j]!=-1)
	    return maxSum[i][j];
	else
	{    
		if(i==n)//到最底层时,距离就是本身 
		{
			maxSum[i][j]=D[i][j];
		} 
		else
		{
			maxSum[i][j]=D[i][j]+max(MaxSum(i+1,j),MaxSum(i+1,j+1));	
		}
		return maxSum[i][j];
    }	
} 

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
		    cin>>D[i][j];
		    maxSum[i][j]=-1;
	    }
	}
	cout<<endl;
	MaxSum(1,1);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
		    cout<<maxSum[i][j]<<" ";
	    }
	    cout<<endl;
	}
	//cout<<MaxSum(1,1);
//	cout<<s;
	//5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
}

 

将各个位置的距离记录下来,省去一次次的迭代。可以极大效率的提高运行速度,注意这里不能每次只存最大量,需要保存所有的值。

4、看到上面记录表,可以考虑将递归改为递推,不用重复迭代那么多次。  

 

#include<iostream>
#include<algorithm>
#define MAX 101

using namespace std;
int D[MAX][MAX];//输入初始矩阵图 
int n;//全局变量 
int maxSum[MAX][MAX];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
		    cin>>D[i][j];
	    }
	}
	for(int i=1;i<=n;i++)
	{
		maxSum[n][i]=D[n][i];//最后一行赋值 
	}
	for(int i=n-1;i>=1;i--)
	{
		for(int j=1;j<=i;j++)
	        maxSum[i][j]=D[i][j]+max(D[i+1][j],D[i+1][j+1]);//	
	} 
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
		    cout<<maxSum[i][j]<<" ";
	    }
	    cout<<endl;
	}
	//cout<<MaxSum(1,1);
//	cout<<s;
	//5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
}

出错的原因是混淆了递推加的是变化后的值,而不是初始值。

#include<iostream>
#include<algorithm>
#define MAX 101

using namespace std;
int D[MAX][MAX];//输入初始矩阵图 
int n;//全局变量 
int maxSum[MAX][MAX];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
		    cin>>D[i][j];
	    }
	}
	for(int i=1;i<=n;i++)
	{
		maxSum[n][i]=D[n][i];//最后一行赋值 
	}
	for(int i=n-1;i>=1;i--)
	{
		for(int j=1;j<=i;j++)
	        maxSum[i][j]=D[i][j]+max(maxSum[i+1][j],maxSum[i+1][j+1]);//比较的是新的数组	
	} 
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
		    cout<<maxSum[i][j]<<" ";
	    }
	    cout<<endl;
	}
	//cout<<MaxSum(1,1);
//	cout<<s;
	//5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
}

5、空间优化

#include<iostream>
#include<algorithm>
#define MAX 101

using namespace std;
int D[MAX][MAX];//输入初始矩阵图 
int n;//全局变量 
int *maxSum;

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
		    cin>>D[i][j];
	    }
	}
    maxSum=D[n];//指向第n行 
	for(int i=n-1;i>=1;i--)
	{
		for(int j=1;j<=i;j++)
	        maxSum[j]=D[i][j]+max(maxSum[j],maxSum[j+1]);//比较的是新的数组	
	} 
    for(int i=1;i<=n;i++)
	    cout<<maxSum[i]<<" "; 
	//cout<<MaxSum(1,1);
//	cout<<s;
	//5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
}

三、

1、错误实例

#include<iostream>//错误实例
#include<algorithm>

using namespace std;
const int Maxn=1010;
int a[Maxn];
int maxLen[Maxn];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		maxLen[i]=1;
	}
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=i-1;j++)
		{
			if(i=2&&a[j]<=a[i])
			{
				maxLen[i]++;
				break;
			}
			else if(a[j]<=a[i]&&a[j]>a[j-1])
			{
				maxLen[i]++;
			}
		}
		cout<<maxLen[i]<<" ";
		
	}
	cout<<endl;
	int Max=maxLen[1]; 
	for(int i=1;i<=n;i++)
	{
		if(maxLen[i]>Max)
		    Max=maxLen[i];
	}
	cout<<Max;
	//7 1 7 3 5 9 4 8
}

上面这段程序是错误的,错误的根源是没有理解清楚该如何递推,只是单纯的比较,并没有归纳到将前一次的比较运用到这次来。  

 2、

#include<iostream>
#include<algorithm>

using namespace std;
const int Maxn=1010;
int a[Maxn];
int maxLen[Maxn];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		maxLen[i]=1;
	}
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=i-1;j++)
		{
			if(a[i]>=a[j])
			    maxLen[i]=max(maxLen[i],maxLen[j]+1);//从小于i的数每个都比较,如果大于,说明上升子序列可以加1,最后比较多组,找出最大的
		}
		cout<<maxLen[i]<<" ";	
	}
	cout<<endl;
	int Max=maxLen[1]; 
	for(int i=1;i<=n;i++)
	{
		if(maxLen[i]>Max)
		    Max=maxLen[i];
	}
	cout<<Max;
	//7 1 7 3 5 9 4 8
}

 

#include<iostream>
#include<algorithm>

using namespace std;
const int Maxn=1010;
int a[Maxn];
int maxLen[Maxn];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		maxLen[i]=1;
	}
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=i-1;j++)
		{
			if(a[i]>=a[j])
			    maxLen[i]=max(maxLen[i],maxLen[j]+1);
		}
		cout<<maxLen[i]<<" ";	
	}
	cout<<endl;
	cout<<*max_element(maxLen+1,maxLen+n+1);//新的找最大值的方法
	//7 1 7 3 5 9 4 8
}

3、最大最小值

#include<iostream>  
#include<algorithm>  
using namespace std;  
  
bool cmp(int a,int b)  
{  
    return a<b;  
}  
int main()  
{  
    int num[]={2,3,1,6,4,5};  
    cout<<"最小值是 "<<*min_element(num,num+6)<<endl;  
    cout<<"最大值是 "<<*max_element(num,num+6)<<endl;  
    cout<<"最小值是 "<<*min_element(num,num+6,cmp)<<endl;  
    cout<<"最大值是 "<<*max_element(num,num+6,cmp)<<endl;  
    return 0;   
}  

s、

四、

#include<iostream>
#include<cstring>
using namespace std;
const int Max=64;
char sz1[1000],sz2[1000];
int maxLen[1000][1000];
int main()
{
	while(cin>>sz1>>sz2)
	{
		int l1=strlen(sz1);
		int l2=strlen(sz2);
		int ntmp;
		for(int i=0;i<=l1;i++)//边界条件,0代表空串 
	        maxLen[i][0]=0;
	    for(int j=0;j<=l2;j++)
	        maxLen[0][j]=0;
	    for(int i=1;i<=l1;i++)
		{
			for(int j=1;j<=l2;j++)
			{
				if(sz1[i-1]==sz2[j-1])
				    maxLen[i][j]=maxLen[i-1][j-1]+1;//i,j 都加1 
				else
				    maxLen[i][j]=max(maxLen[i][j-1],maxLen[i-1][j]);
			}
		}
		for(int i=0;i<=l1;i++)
		{
		   for(int j=0;j<=l2;j++)
	        {
		       cout<<maxLen[i][j]<<" ";
		    }
			cout<<endl; 
	    }
		cout<<maxLen[l1][l2]<<endl; 
	}
	// abcfbc abfcab
}

0的存在是边界,整个矩阵可以看出并不是对称矩阵,所以else的判断条件尤为重要。

五、

 

#include <iostream>  
#include <cstdio>  
#include <cstring>  
  
using namespace std;  
const int maxn=1000;  
const int inf=0x3f3f3f3f;  
int n;  
char c[maxn];  
int dp[maxn][maxn];  
int num[maxn][maxn];  
int m;  
  
int NUM(int x,int y) //从x位置到y位置的数 
{  
    if(num[x][y]!=-1)  
    {  
        return num[x][y];  
    }  
    int sum=0;  
    for(int i=x;i<y;i++)  
    {  
        sum=sum*10+c[i]-'0';  
    }  
    num[x][y]=sum;  
    return sum;  
}  
int DP(int p,int x) //p个字符,x个加号; 
{  
    if(dp[p][x]!=-1)  //一开始是等于-1;不等于-1说明计算过了 
    {  
        return dp[p][x];  
    }  
  
    if(x==0) //没有加号 
    {  
        dp[p][0]=NUM(0,p);  //字符串变数字 
        return dp[p][0];  
    }  
    dp[p][x]=inf;  
    for(int k=p-1;k>=x;k--)//k会发生变化,控制加号可能出现的位置。大于x是为了给加号留够位置。 
    {  
        dp[p][x]=min(dp[p][x],DP(k,x-1)+NUM(k,p));//dp在多次循环比较中找到最小的 !循环递归化 
    }  
    return dp[p][x];   
}  
  
int main() 
{    
    while(cin>>c)//输入字符  
    {  
        memset(dp,-1,sizeof(dp)); //全部赋为-1; 
        memset(num,-1,sizeof(num));  
        scanf("%d",&m);  //输入加号个数 
        n=strlen(c);  
        printf("%d\n",DP(n,m)); //n个字符,m个加号 
    }  
    return 0;  
}  

#include<iostream>
#include<string>
#include<cstring>
using namespace std;

const int Max=100;
const int N=20;
const int inf=0x3f3f3f3f;
int mindit[Max][N];//存放Max个字符,N个加号 ,最小值 
int n;
int L;
string str;

int Num(int x,int y)//k位置到L位置 
{
	int sum=0;  
	for(int i=x;i<y;i++)  
	{  
	    sum=sum*10+str[i]-'0';  
	}  
	return sum;  
    
}

int MinDit(int P,int x)
{
    if(mindit[P][x]!=-1)
	    return mindit[P][x];
	else if(x==0)//边界条件的核心 
	{
		return Num(0,P);
	}
	   
	else
	{
		mindit[P][x]=inf;
		for(int k=P-1;k>=x;k--)
		{
			mindit[P][x]=min(mindit[P][x],MinDit(k,x-1)+Num(k,P));
		}
		return mindit[P][x];
    }	
}

int main()
{
	getline(cin,str);//数字符串 
	cin>>n;//加号个数 
	memset(mindit,-1,sizeof(mindit));//二维数组赋值同样值方式 
	L=str.length();
	cout<<MinDit(L,n)<<endl;
}

换用string 和去掉和的求解空间。

六、

1、递归

#include<iostream>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
  
//递归方法,求解最长回文子序列  
int lps(char *str, int i, int j) //字符串i和j之间的回文字符长度 
{  
    if (i == j)  
        return 1;   //只有一个元素,回文长度为1  
    if (i > j) 
	    return 0;   //因为只计算序列str[i....j]  
    //如果首尾相同  
    if (str[i] == str[j])  
        return lps(str, i + 1, j - 1) + 2;  
    //如果首尾不同  
    else
	    return max(lps(str, i, j - 1), lps(str, i + 1, j));  
}  
  
int main()  
{  
    char str[] = "cabbeaf";  
    int n = strlen(str);  
    int res = lps(str, 0, n-1);  
    cout << res<< endl;  
    return 0;  
}  

2、

#include<iostream>  
#include<cstring>  
#include<algorithm>  
using namespace std;
const int Maxn=100; 
int Len[Maxn][Maxn]; 
  
//递归方法,求解最长回文子序列  ,自下而上 
int lps(char *str, int n) //字符串i和j之间的回文字符长度 
{  
    memset(Len,0,sizeof(Len));//赋值 Len[i][j]是i和j位置处的回文长度 
    int temp;
    for(int i=0;i<n;i++)
    {
    	Len[i][i]=1;//1个长度 
	}
	for(int i=1;i<n;i++)
	{
	    for(int j=0;j+i<n;j++)
		{
			if(str[j+i]==str[j])
			{
				Len[j][j+i]=Len[j+1][j+i-1]+2;//初设值为0,才对 
			}
			else
			{
			    Len[j][j+i]=max(Len[j+1][j+i],Len[j][j+i-1]);	
			} 
		}	
	} 
	return Len[0][n-1];
}  
  
int main()  
{  
    char str[] = "cabbeaf"; 
    int n = strlen(str);  
    int res = lps(str,n);  
    cout << res<< endl;  
    return 0;  
}  

动态规划的思想就是用矩阵记录迭代的值,不用重复迭代,关键是如何循环给矩阵赋值。该题就是从小到大的间距给矩阵赋值,使得下次的赋值能用上次的赋值。

3、求解回文数的个数

#include <bits/stdc++.h>
 
using namespace std;
typedef long long LL;
const int maxn = 50 + 5;
LL dp[maxn][maxn];
char s[maxn];

int main() 
{
    scanf("%s", s + 1);
    int len = strlen(s + 1);
    memset (dp, 0, sizeof(dp));//初值为0; 
    for(int i = 1; i <= len; i++)
	{
        for(int l = 1; l + i - 1 <= len; l++) 
		{
            int r = l + i - 1;//dp[1][1],dp[2][2],dp[3][3]
                            //dp[1][2],dp[2][3]
            dp[l][r] += dp[l + 1][r];
            dp[l][r] += dp[l][r - 1];
            if (s[l] == s[r]) 
			    dp[l][r] += 1;
            else 
			    dp[l][r] -= dp[l + 1][r - 1];
        }
    }
    printf ("%lld\n", dp[1][len]);
    return 0;
}

 

  

  

 

  

 

  

  

  

  

  

  

  

 

  

  

  

  

  

  

  

 

posted on 2018-04-10 13:35  箬笠蓑衣  阅读(260)  评论(0编辑  收藏  举报