educoder算法设计与分析 实验三

实验三 动态规划实验

  • 第1关:编程实现矩阵连乘问题的求解
  • 第2关:编程实现最大子段和问题的求解(分别采用分治法和动态规划法求解)
  • 第3关:0-1背包
  • 第4关:最长单调子序列
  • 第5关:最长公共子序列(LCS)

第1关:编程实现矩阵连乘问题的求解

题目描述:

在计算矩阵连乘积时,加括号的方式对计算量有影响。
 
例如: 有三个矩阵A1,A2,A3连乘,它们的维数分别为
10100,1005,550。用第一种加括号方式(A1A2)A3计算,则所需数乘次数为101005+10550=7500。用第二种加括号方式A1(A2A3)计算,需要100550+10100*50=75000次数乘。

输入连乘矩阵的个数,每个矩阵的维数。要求输出最少数乘次数。

相关知识
educoder算法设计与分析 实验三_第1张图片
输入格式

第一行输入一个n,代表有n个矩阵
接下来n行,每行输入两个数a,b,代表每个矩阵的维度。
0

输出格式

输出一个数,代表最小数乘次数。

测试输入:

6
30 35
35 15
15 5
5 10
10 20
20 25

预期输出:

15125

代码

#include

int main(){
     
	int n;
	scanf("%d",&n);
	int a[n][2];
	int b[n][n]={
     0};
	for(int i=0;i<n;i++){
     
	    scanf("%d %d",&a[i][0],&a[i][1]);   
	}
	
	for(int i=1;i<n;i++){
     
	    for(int j=0;j<n-i;j++){
     
	      b[j][j+i]=b[j][j]+b[j+1][j+i]+a[j][0]*a[j][1]*a[j+i][1];         
	      int k=j+1;
	      for(;k<j+i;k++){
     
	              int t=b[j][k]+b[k+1][j+i]+a[j][0]*a[k][1]*a[j+i][1];
	                if(t<b[j][j+i]) {
     
	                    b[j][j+i]=t;
	                }
	      //也可以直接三元操作符:b[j][j+i]=b[j][k]+b[k+1][j+i]+a[j][0]*a[k][1]*a[j+i][1]
	      }
	
	    }
	        
	}
	printf("%d",b[0][n-1]);
	return 0;
}

第2关:编程实现最大子段和问题的求解(分别采用分治法和动态规划法求解)

题目描述:

对于给定序列a1,a2,a3……an,寻找它的某个连续子段,使得其和最大。如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20。

输入格式

第一行输入一个n,代表有n个数
下面一行输入n个数,代表序列
0 序列中的数的范围为[-2000,2000]

输出格式

输出一个数,代表最大字段和。

测试输入:

6
-2 11 -4 13 -5 -2

预期输出:

20

代码

第一种:分治法

#include

int Largestsubsection(int a[],int m,int n){
     
		if(n==m){
     
			return a[n];
		}
		int cent=(m+n)/2;
		int d=Largestsubsection(a,m,cent)>Largestsubsection(a,cent+1,n)?Largestsubsection(a,m,cent):Largestsubsection(a,cent+1,n);
		int left=0,s1=0;
		for(int i=cent;i>=m;i--){
     
			left+=a[i];
			if(left>s1){
     
			    s1=left;
			}
		}
		int right=0,s2=0;
		for(int i=cent+1;i<=n;i++){
     
			right+=a[i];
			if(right>s2){
     
			    s2=right;
			}
		}
		int sum=s1+s2;
		return d>sum?d:sum;
}

int main(){
     
	int n;
	scanf("%d",&n);
	int a[n];
	for(int i=0;i<n;i++){
     
		scanf("%d",&a[i]);
	}
	printf("%d",Largestsubsection(a,0,n-1));
	return 0;

}

第二种:动态规划法

#include

int main(){
     
	int n;
	scanf("%d",&n);
	int a[n][2];
	int max=0;
	for(int i=0;i<n;i++){
     
		scanf("%d",&a[i][0]);
		if(i==0){
     
			a[i][1]=a[i][0];
		}
		else{
     
			a[i][1]=a[i-1][1]+a[i][0]>a[i][0]?a[i-1][1]+a[i][0]:a[i][0];
		}
		
		max=max>a[i][1]?max:a[i][1];
		
	}
	printf("%d",max);
	return 0;
	
}

第3关:0-1背包

题目描述:

给定n个物品和一背包,物品i的重量是wi,其价值为vi,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?

相关知识

动态规划

输入格式

第一行输入一个n,c,代表有n个物品背包容量为c
接下来n行,每行输入wi,和vi
其中0

输出格式

输出一个数,代表最大价值

测试输入:

4 8
2 3
3 4
4 5
5 6

预期输出:

10

代码

#include

int main(){
     
    int n,c;
    scanf("%d %d",&n,&c);
    int a[n][2],b[n][c+1]={
     0};//一个存题目数据,一个构建最优解。
    for(int i=0;i<n;i++){
     
        scanf("%d %d",&a[i][0],&a[i][1]);
        for(int j=1;j<c+1;j++){
     
            if(i==0){
     
                  if(a[i][0]>j){
     
                       b[i][j]=0;
                  }
                  else{
     
                       b[i][j]=a[i][1];
                  }          
                }
            else{
     
                  if(a[i][0]<=j){
     
                        b[i][j]=b[i-1][j]>a[i][1]+b[i-1][j-a[i][0]]?b[i-1][j]:a[i][1]+b[i-1][j-a[i][0]];
                    }
                  else{
     
                        b[i][j]=b[i-1][j];
                    }          
                }
        }

    }
    printf("%d",b[n-1][c]);
    return 0;

}

第4关:最长单调子序列

题目描述
给定一个序列,求这个序列的最长上升子序列的长度,并输出这个最长上升子序列,题目保证,最长上升子序列只有一个。

相关知识
最长上升子序列

输入格式
第一行输入一个n,代表序列长度
第二行输入n个值,代表这个序列
0 -1000<序列内的数<1000

输出格式
第一行输出一个数,代表最长上升子序列的长度。
第二行打印这个子序列。

测试输入:
8
5 2 8 6 3 6 5 7

输出
4
2 3 6 7

代码

#include

int main(){
     
	 int n;
	 scanf("%d",&n);
	 int m[n][3];
	 m[0][1]=1;
	 m[0][2]=0;
	 for(int i=0;i<n;i++){
     
		scanf("%d",&m[i][0]);
		if(i!=0){
     
			int k=i-1;
			while(k>=0){
       
				if(m[i][0]>m[k][0]){
     
					m[i][1]=m[k][1]+1;
					m[i][2]=k;
					break;
				}
				k--;
			}
			if(k<0){
     
			    m[i][1]=1;
			    m[i][2]=i;
			}
		}
	 }
	 
	int max=m[0][1],j=0;
	for(int i=0;i<n;i++){
     
	      if(m[i][1]>=max){
     
	             max=m[i][1];
	             j=i;
	      }
	 } 
	printf("%d\n",max);   
	int a[max],c=max;
	while(m[j][2]!=j){
     
	     max--;
	     a[max]=m[j][0];
	     j=m[j][2];
	}
	a[max-1]=m[j][0];
	for(int i=0;i<c;i++){
     
	  printf("%d ",a[i]);
	
	}
    return 0;
}

第5关:最长公共子序列(LCS)

题目描述

给定两个序列X=ABCBDAB, Y=BDCABA,求X和Y的最长公共子序列

相关知识

动态规划

输入格式

两行,每行为一个长度不超过500的字符串(全为大写字符串)

输出格式

输出一个数,最长公共子序列的长度,若不存在公共子序列,则输出0。

测试输入

ABCBDAB
BDCABA

测试输出

4

代码

方法一:
(自己想的)

#include
#include

int main(){
     
    char x[500]={
     '\0'},y[500]={
     '\0'};
    scanf("%s",x);
    scanf("%s",y);
    int m=strlen(x),n=strlen(y);
    int a[m][n];
    for(int i=0;i<m;i++){
     
        for(int j=0;j<n;j++){
     
            if(x[i]==y[j]){
     
	            a[i][j]=1;
            }
	        else{
     
	            a[i][j]=0;
	        }
        }
    }
    int max=0;
    for(int i=0;i<m;i++){
     
        for(int j=0;j<n;j++){
     
		      if(a[i][j]==1){
     
			      int t=1,k=i+1,l=j+1;
			      while(k<m&l<n){
     
			        int g=l;//记录l
				    while(l<n&&a[k][l]==0){
     
				           l++;
				    }    
				    if(a[k][l]==1){
      t++;l++;}
				    else{
     
                            l=g; //即本排没有1
				    }
				           k++;
			        }
			        max=max>t?max:t;
		      }
	    }       
     }
	printf("%d",max);
	return 0;
}

方法二:
(算法课上讲的DP方法)

#include
#include

int main(){
     
    char x[500]={
     '\0'},y[500]={
     '\0'};
    scanf("%s",x);
    scanf("%s",y);
    int m=strlen(x),n=strlen(y);
    int a[m+1][n+1]={
     0};
    for(int i=1;i<m+1;i++){
     
         for(int j=1;j<n+1;j++){
     
                if(x[i]==y[j]){
     

                    a[i][j]=a[i-1][j-1]+1;
                }
                 else{
     

                     a[i][j]=a[i][j-1]>a[i-1][j]?a[i][j-1]:a[i-1][j];
                 }          

         }  

    }
    printf("%d",a[m][n]);
    return 0;

}

注:答案不唯一,仅供参考。

你可能感兴趣的:(算法,动态规划)