用动态规划法解决最大子段和问题

二、实验目的: 

      课程设计是《算法分析与设计》课程不可缺少的重要实践性环节。通过实践教学,要达到以下目的:

(1)使学生掌握动态规划法思想

(2)使学生掌握以抽象数据类型为模块的面向对象程序设计方法;

(3)使学生提高对实际问题的分析、设计和实现能力;

(4)为学生后续课程的学习及课程设计打下坚实的实践基础。

 三、使用的策略:

 动态规划法思想

 

四、实验内容:

(一) 问题描述

给定由n个整数(可能为负整数)组成的序列a1,a2,a3,···,an,求该序列的子段和的最大值。当所有整数均为负整数是定义其最大子段和为0,一次定义,所求的最优质值为:max{0、max子段和}。

 

 

(二) 算法描述

动态规划法的基本思想:

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。

算法设计:

#include "stdafx.h"
int MaxSum(int a[],int n,int &Start,int&End){
       intsum=0;
       int*b,t;
       b=newint[n+1];
       b[0]=0;
       for(inti=1;i<=n;i++){
              if(b[i-1]>0){
                     b[i]=b[i-1]+a[i];
              }
              else {
                     b[i]=a[i];t=i;
              }
              if(b[i]>sum){
                     sum=b[i];
                     Start=t;
                     End=i;
              }
       }
       delete[]b;
       returnsum;
}
 
int main(int argc, char* argv[])
{
       inta[7]={0,-2,11,-4,13,-5,-2},sum,Start,End,i;
       sum=MaxSum(a,6,Start,End);
       for(i=Start;i<=End;i++){
              printf("%d ",a[i]);
       }
       printf("\n%d\n",sum);
       getchar();
       getchar();
       return0;
}

    用分支界限法解决最大子段和问题

二、实验目的: 

      课程设计是《算法分析与设计》课程不可缺少的重要实践性环节。通过实践教学,要达到以下目的:

(1)使学生掌握分支界限法思想

(2)使学生掌握以抽象数据类型为模块的面向对象程序设计方法;

(3)使学生提高对实际问题的分析、设计和实现能力;

(4)为学生后续课程的学习及课程设计打下坚实的实践基础。

 三、使用的策略:

     分支界限法

四、实验内容:

(一) 问题描述

在下图所给的有向图G中,每一边都有一个非负边权。要求图G的从源顶点s到目标顶点t之间的最短路径。

 

(二) 算法描述

分支界限法的基本思想:

分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。

在分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。

 此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。

算法设计:

#include<iostream>
#include<vector>
#include<queue>
#include<limits>
using namespacestd;
 
struct node_info
{
public:
    node_info (int i,int w) 
        : index (i), weight (w) {}
    node_info () 
        : index(0),weight(0) {}
    node_info (const node_info & ni) 
        : index (ni.index), weight (ni.weight){}
 
    friend 
    bool operator < (const node_info<h,const node_info& rth) {
        return lth.weight > rth.weight ; // 为了实现从小到大的顺序
    }
 
public:
    int index; // 结点位置
    int weight; // 权值
};
 
struct path_info
{
public:
    path_info ()
        : front_index(0), weight(numeric_limits<int>::max()) {}
 
public:
    int front_index;
    int weight;
};
 
// single sourceshortest paths
classss_shortest_paths
{
     
public:
    ss_shortest_paths (constvector<vector<int> >& g,int end_location) 
        :no_edge (-1), end_node (end_location),node_count (g.size()) , graph (g) 
    {}
 
    // 打印最短路径
    void print_spaths () const {
        cout << "min weight : "<< shortest_path << endl;
        cout << "path: " ;
        copy(s_path_index.rbegin(),s_path_index.rend(),
            ostream_iterator<int> (cout," "));
        cout << endl;
    }
 
    // 求最短路径
    void shortest_paths () {
        vector<path_info>path(node_count);
       priority_queue<node_info,vector<node_info> > min_heap;
        min_heap.push (node_info(0,0));    // 将起始结点入队
 
        while (true) {
            node_info top = min_heap.top();    // 取出最大值
            min_heap.pop ();
 
            // 已到达目的结点
            if (top.index == end_node) {
                break ;
            }
            // 未到达则遍历
            for (int i = 0; i < node_count;++ i) {
                // 顶点top.index和i间有边,且此路径长小于原先从原点到i的路径长 
                if (graph[top.index][i] !=no_edge && 
                    (top.weight +graph[top.index][i]) < path[i].weight) {
                    min_heap.push (node_info(i,top.weight + graph[top.index][i]));
                    path[i].front_index =top.index;
                    path[i].weight = top.weight+ graph[top.index][i];
                }
            }
            if (min_heap.empty()) {
                break ;
            }
        }
 
        shortest_path = path[end_node].weight;
        int index = end_node;
        s_path_index.push_back(index) ;
        while (true) {
            index = path[index].front_index ;
            s_path_index.push_back(index);
            if (index == 0) {
                break;
            }
        }
    }
 
private:
    vector<vector<int> >    graph ;            // 图的数组表示
    int                        node_count;        // 结点个数
    const int                no_edge;        // 无通路
    const int                end_node;        // 目的结点
    vector<int>                s_path_index;    // 最短路径
    int                        shortest_path;    // 最短路径
};
 
int main()
{
    const int size = 11; 
    vector<vector<int> > graph(size);
    for (int i = 0;i < size; ++ i) {
        graph[i].resize (size);
    }
    for ( i = 0;i < size; ++ i) {
        for (int j = 0;j < size; ++ j) {
            graph[i][j] = -1;
        }
    }
    graph[0][1] = 2;
    graph[0][2] = 3;
    graph[0][3] = 4;
    graph[1][2] = 3;
    graph[1][5] = 2;
    graph[1][4] = 7;
    graph[2][5] = 9;
    graph[2][6] = 2;
    graph[3][6] = 2;
    graph[4][7] = 3;
    graph[4][8] = 3;
    graph[5][6] = 1;
    graph[5][8] = 3;
    graph[6][9] = 1;
    graph[6][8] = 5;
    graph[7][10] = 3;
    graph[8][10] = 2;
    graph[9][8] = 2;
    graph[9][10] = 2;
 
    ss_shortest_paths ssp (graph, 10);
    ssp.shortest_paths ();
    ssp.print_spaths ();
       getchar();
    return 0;
}

    
 
 

      
 用分治法解决最大子段和问题 

 
二、实验目的: 
      课程设计是《算法分析与设计》课程不可缺少的重要实践性环节。通过实践教学,要达到以下目的:
(1)使学生掌握分治法思想
(2)使学生掌握以抽象数据类型为模块的面向对象程序设计方法;
(3)使学生提高对实际问题的分析、设计和实现能力;
(4)为学生后续课程的学习及课程设计打下坚实的实践基础。
 三、使用的策略:
     分治法算法
四、实验内容:
(一) 问题描述
给定由n个整数(可能为负整数)组成的序列a1,a2,a3,···,an,求该序列的子段和的最大值。当所有整数均为负整数是定义其最大子段和为0,一次定义,所求的最优质值为:max{0、max子段和}。

(二) 算法描述

分治算法的基本思想:

分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成

算法设计:
#include "stdafx.h"
 
int MAXSubsum(int a[],int left,int right){
       intsum=0,center,LeftSum,RightSum;
       ints1,lefts,s2,rights,i;
       if(left==right)
          sum=a[left]>0?a[left]:0;
       else{
         center=(left+right)/2;
       //求出第(1)种情况的最大字段和
 
         LeftSum=MAXSubsum(a,left,center);
       //求出第(2)种情况的最大字段和
 
         RightSum=MAXSubsum(a,center+1,right);
       //求出第(3)种情况的最大字段和
 
       s1=0,lefts=0;
       for(i=center;i>=left;i--){
              lefts+=a[i];
              if(lefts>s1)s1=lefts;
       }
       //第三种情况左边的和
 
         s2=0,rights=0;
       for(i=center+1;i<=right;i++)
       {
               rights+=a[i];
               if(rights>s2)s2=rights;
       }
       //右边的和
 
 
        sum=s1+s2;//保存了第三种情况字段和
        if(sum<LeftSum)sum=LeftSum;
        if(sum<RightSum)sum=RightSum;
       }
       returnsum;
}
 
int main(int argc, char* argv[])
{
       inta[7]={0,-2,11,-4,13,-5,-2},sum;
       sum=MAXSubsum(a,1,6);
       printf("%d\n",sum);
       getchar();
       getchar();
       return0;
}

用回溯题算法解决背包问题

二、实验目的: 

      课程设计是《算法分析与设计》课程不可缺少的重要实践性环节。通过实践教学,要达到以下目的:

(1)使学生掌握回溯法的定义

(2)使学生掌握以抽象数据类型为模块的面向对象程序设计方法;

(3)使学生提高对实际问题的分析、设计和实现能力;

(4)为学生后续课程的学习及课程设计打下坚实的实践基础。

 三、使用的策略:

      回溯算法                      

四、实验内容:

(一) 问题描述

给定一个最大重量为M的背包和N种物品,已知第i种物品是Wi公斤,其价值为Vi元,编程确定一个装货方案,是的装入背包中的所有物品总价值最大。

(二) 算法描述

回溯算法解决方案:

l 回溯算法的基本思想

回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

设计算法:

#include "stdafx.h"  
#include <iostream>   
using namespace std;   
 
using namespace std;
#define max(a,b)((a)>(b)?(a):(b))
 
int bestValue=0;
 
void backSearch(int *weight,int *value,int capacity,int num,int *mark,intstep,int tempValue,int tempWeight)
{
 int i;
 
 if (step>num)
 {
  if (tempValue>bestValue)
  {
   bestValue=tempValue;
  cout<<bestValue<<endl;
   for (i=1;i<=num;i++)
   {
   cout<<mark[i]<<" ";
   }
   cout<<endl;
  }
  return ;
 }
 else
 {
  if(tempWeight+weight[step]<=capacity)
  {
   mark[step]=1;
  backSearch(weight,value,capacity,num,mark,step+1,tempValue+value[step],tempWeight+weight[step]);
  }
  mark[step]=0;//注意
 backSearch(weight,value,capacity,num,mark,step+1,tempValue,tempWeight);
 }
}
 
int main()
{
    int capacity,num;
    int *weight,*value,*mark;
    int i;
   
    printf("请输入包的容量:");
   scanf("%d",&capacity);
    printf("请输入物品的数量:");
    scanf("%d",&num);
       
    weight=(int*)malloc(sizeof(int)*(num+1));
    value=(int*)malloc(sizeof(int)*(num+1));
 mark=(int*)malloc(sizeof(int)*(num+1));
 
    for(i=1;i<=num;i++)
    {
  printf("请输入第%d件物品的重量:",i);
 scanf("%d",weight+i);  
  printf("请输入第%d件物品的价值:",i);
  scanf("%d",value+i);
  
  printf("\n");           
    }
 
 backSearch(weight,value,capacity,num,mark,1,0,0);
    printf("书包可容纳的最大价值为:%d\n",bestValue);
 
    free(weight);
    free(value); 
 free(mark);
 
    system("pause");
    return 0;  
}

用贪心算法解决背包问题   

二、实验目的: 

      课程设计是《算法分析与设计》课程不可缺少的重要实践性环节。通过实践教学,要达到以下目的:

(1)使学生掌握贪心算法的定义

(2)使学生掌握以抽象数据类型为模块的面向对象程序设计方法;

(3)使学生提高对实际问题的分析、设计和实现能力;

(4)为学生后续课程的学习及课程设计打下坚实的实践基础。

 三、使用的策略:

     贪心算法

四、实验内容:

(一) 问题描述

给定一个最大重量为M的背包和N种物品,已知第i种物品是Wi公斤,其价值为Vi元,编程确定一个装货方案,是的装入背包中的所有物品总价值最大。

(二) 算法描述

贪心算法解决方案:

l 贪心算法的基本思想

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解

算法设计:

#include "stdafx.h"  
#include <iostream>   
using namespace std;   
  
const int N = 3;  
  
void Gr(int n,float M,float v[],floatw[],float x[]);  
 
int main()  
{ 
   float M = 50;//背包所能容纳的重量   
  float w[] = {10,20,30}; 
   float v[] = {100,250,300};  
  
   float x[N+1];  
  
   cout<<"背包所能容纳的重量为:"<<M<<endl;  
   cout<<"待装物品的重量和价值分别为:"<<endl;  
   for(int i=1; i<=N; i++)  
   {  
       cout<<"["<<i<<"]:("<<w[i]<<","<<v[i]<<")"<<endl;  
   }  
     
   Gr(N,M,v,w,x);  
  
  cout<<"选择装下的物品比例如下:"<<endl;  
   for( i=1; i<=N; i++)  
   {  
       cout<<"["<<i<<"]:"<<x[i]<<endl;  
   }  
 getchar();
  return 0;  
} 
  
void Gr(int n,float M,float v[],floatw[],float x[])  
{ 
  
   int i;  
   for (i=1;i<=n;i++)  
   {  
       x[i]=0;//初始化数组x[]  
  }  
 
  float c=M;  
  for (i=1;i<=n;i++)//物品整件被装下,x[i]=1  
  {  
       if (w[i]>c)  
      {  
            break;  
       }  
      x[i]=1;  
      c-=w[i]; 
} 
 
  //物品i只有部分被装下  
  if (i<=n)  
  {  
      x[i]=c/w[i];  
  }  
}