主定理,动态规划与分治,贪心算法,回溯

主定理,动态规划与分治,贪心算法,回溯

 

动态规划与分治:

 

主定理,动态规划与分治,贪心算法,回溯

 

动态规划与贪心:

 

主定理,动态规划与分治,贪心算法,回溯

 

分支界限法与回溯的分析:

 

主定理,动态规划与分治,贪心算法,回溯

 

主定理,动态规划与分治,贪心算法,回溯

 

贪心算法:https://blog.csdn.net/weixin_41413441/article/details/79195259

 

 

0-1背包问题 —— 四种解法解题

https://www.cnblogs.com/xym4869/p/8513801.html

 

 

贪心算法之活动安排问题:

 

#include <iostream>
using namespace std;
void  GreedSelector(int n,int s[],int f[],bool A[]);
const int n = 11;
int main()
{
    int s[12]={0,1,3,0,5,3,5,6,8,8,2,12},f[12]={0,4,5,6,7,8,9,10,11,12,13,14};
    bool A[n+1];
    GreedSelector(n,s,f,A);
    cout<<"最大相容活动安排为:"<<endl;
    for(int i=1;i<=n;i++)
    {
       if(A[i])
        {
            cout<<"["<<i<<"]:"<<"("<<s[i]<<","<<f[i]<<")"<<endl;
        }
    }

    return 0;
}
void  GreedSelector(int n,int s[],int f[],bool A[])
{
    A[1]=true;
    int j=1;
    for (int i=2;i<=n;i++)
    {

        if(s[i]>=f[j])
    {
        A[i]=true ;
        j=i;
    }
    else
    {
        A[i]=false;
    }
    }
}

 

#include <stdio.h>
#include <stdlib.h>
typedef int bool;
#define true 1
#define false 0
int  GreedSelector(int n,int s[],int f[],bool A[])
{
    A[1]=true;
    int i,j=1,count=1;
    for (i=2;i<=n;i++)
    {

        if(s[i]>=f[j])
    {
        A[i]=true ;
        j=i;
 count++;
    }
    else A[i]=false;
    }
return count;
}

int  main()
{
    int i,n=11;
    int p;
    int s[12]={0,1,3,0,5,3,5,6,8,8,2,12},f[12]={0,4,5,6,7,8,9,10,11,12,13,14};
    bool A[12];
    //printf("输入节目数:\n");
    //scanf("%d",&n);
    /*printf("请依次输入节目的开始和结束时间\n");
    for(i=0;i<n;i++)
    {
        scanf("%d %d",&s[i],&f[i]);
    }*/
    p=GreedSelector(n,s,f,A);
    printf("安排的节目个数为:%d\n",p);
    printf("节目的选取情况为(0表示不选 1表示选取):\n");
    for(i=1;i<=n;i++)
        printf("%d ",A[i]);
    printf("\n");
    return 0;
}

 

 

动态规划法求解0/1背包问题:

#include <stdio.h>
#define N 100
#define MAX(a,b) a < b ? b : a
using namespace std;

struct goods{
int sign;//物品序号
int wight;//物品重量
int value;//物品价值
};

int n,bestValue,cv,cw,C;//物品数量,价值最大,当前价值,当前重量,背包容量
int X[N],cx[N];//最终存储状态,当前存储状态
struct goods goods[N];

int KnapSack(int n,struct goods a[],int C,int x[]){
    int V[N][10*N];
    for(int i = 0; i <= n; i++)//初始化第0列
        V[i][0] = 0;
    for(int j = 0; j <= C; j++)//初始化第0行
        V[0][j] = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= C; j++)
        if(j < a[i-1].wight)
            V[i][j] = V[i-1][j];
        else
            V[i][j] = MAX(V[i-1][j],V[i-1][j-a[i-1].wight] + a[i-1].value);

    for(int i = n,j = C; i > 0; i--){
        if(V[i][j] > V[i-1][j]){
            x[i-1] = 1;
            j = j - a[i-1].wight;
        }
        else
            x[i-1] = 0;
    }
    return V[n][C];
}
int main()
{
    printf("物品种类n:");
    scanf("%d",&n);
    printf("背包容量C:");
    scanf("%d",&C);
    for(int i = 0; i < n; i++){
        printf("物品%d的重量w[%d]及其价值v[%d]:",i+1,i+1,i+1);
        scanf("%d%d",&goods[i].wight,&goods[i].value);
    }
    int sum2 = KnapSack(n,goods,C,X);
     printf("动态规划法求解0/1背包问题:\nX=[");
     for(int i = 0; i < n; i++)
        printf("%d",X[i]);
		//cout<<X[i]<<" ";//输出所求X[n]矩阵
     printf("]   装入总价值%d\n", sum2);
     return 0;
}

 

 

回溯法求解0/1背包问题:

#include <iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>

using namespace std;

#define N 100

struct goods{
int wight;//物品重量
int value;//物品价值
};

int n,bestValue,cv,cw,C;//物品数量,价值最大,当前价值,当前重量,背包容量
int X[N],cx[N];//最终存储状态,当前存储状态
struct goods goods[N];

int BackTrack(int i){
    if(i > n-1){
        if(bestValue < cv){
            for(int k = 0; k < n; k++)
                X[k] = cx[k];//存储最优路径
            bestValue = cv;
        }
        return bestValue;
    }
    if(cw + goods[i].wight <= C){//进入左子树
        cw += goods[i].wight;
        cv += goods[i].value;
        cx[i] = 1;//装入背包
        BackTrack(i+1);
        cw -= goods[i].wight;
        cv -= goods[i].value;//回溯,进入右子树
    }
    cx[i] = 0;//不装入背包
    BackTrack(i+1);
    return bestValue;
}

bool m(struct goods a, struct goods b){
    return (a.value/a.wight) > (b.value/b.wight);
}

int KnapSack3(int n, struct goods a[], int C,int x[N]){
    memset(x,0,sizeof(x));
    sort(a,a+n,m);//将各物品按单位重量价值降序排列
    BackTrack(0);
    return bestValue;
}
int main()
{
    printf("物品种类n:");
    scanf("%d",&n);
    printf("背包容量C:");
    scanf("%d",&C);
    for(int i = 0; i < n; i++){
        printf("物品%d的重量w[%d]及其价值v[%d]:",i+1,i+1,i+1);
        scanf("%d%d",&goods[i].wight,&goods[i].value);
    }
    int sum3 = KnapSack3(n,goods,C,X);
    printf("回溯法求解0/1背包问题:\nX=[");
    for(int i = 0; i < n; i++)
        cout << X[i] <<" ";//输出所求X[n]矩阵
    printf("]   装入总价值%d\n",sum3);
    return 0;
}

 

 

 

分支限界法求解背包问题 :

#include<iostream>
#include<algorithm>
using namespace std;
#define N 100 //最多可能物体数
struct goods  //物品结构体
{
    int sign;  //物品序号
    int w; //物品重量
    int p; //物品价值
}a[N];

bool m(goods a,goods b)
{
    return (a.p/a.w)>(b.p/b.w);
}

int max(int a,int b)
{
    return a<b?b:a;
}

int n,C,bestP=0,cp=0,cw=0;

int X[N],cx[N];

struct KNAPNODE   //状态结构体
{
    bool s1[N]; //当前放入物体
    int k;     //搜索深度
    int b; //价值上界
    int w; //物体重量
    int p; //物体价值
};

struct HEAP   //堆元素结构体
{
    KNAPNODE *p;//结点数据
    int b;        //所指结点的上界
};

//交换两个堆元素
void swap(HEAP &a, HEAP&b)
{
    HEAP temp = a;
    a = b;
    b = temp;
}

//堆中元素上移
void mov_up(HEAP H[], int i)
{
    bool done = false;
    if(i!=1){
       while(!done && i!=1){
           if(H[i].b>H[i/2].b){
              swap(H[i], H[i/2]);
           }else{
              done = true;
           }
           i = i/2;
       }
    }
}

//堆中元素下移
void mov_down(HEAP H[], int n, int i)
{
    bool done = false;
    if((2*i)<=n){
       while(!done && ((i = 2*i) <= n)){
           if(i+1<=n && H[i+1].b > H[i].b){
              i++;
           }

           if(H[i/2].b<H[i].b){
              swap(H[i/2], H[i]);
           }else{
              done = true;
           }
       }
    }
}

//往堆中插入结点
void insert(HEAP H[], HEAP x, int &n)
{
    n++;
    H[n] = x;
    mov_up(H,n);
}

//删除堆中结点
void del(HEAP H[], int &n, int i)
{
    HEAP x, y;
    x = H[i]; y = H[n];
    n --;
    if(i<=n){
       H[i] = y;
       if(y.b>=x.b){
           mov_up(H,i);
       }else{
           mov_down(H, n, i);
       }
    }
}

//获得堆顶元素并删除
HEAP del_top(HEAP H[], int&n)
{
    HEAP x = H[1];
    del(H, n, 1);
    return x;
}

//计算分支节点的上界
void bound( KNAPNODE* node,int M, goods a[], int n)
{
    int i = node->k;
    float w = node->w;
    float p = node->p;
    if(node->w>M){   //  物体重量超过背包载重量
       node->b = 0;   //  上界置为0
    }else{
       while((w+a[i].w<=M)&&(i<n)){  
           w += a[i].w;   // 计算背包已装入载重
           p += a[i++].p; //    计算背包已装入价值
       }
       if(i<n){
           node->b = p + (M - w)*a[i].p/a[i].w;
       }else{
           node -> b = p;
       }
    }
}

//用分支限界法实现0/1背包问题
int KnapSack4(int n,goodsa[],int C, int X[])
{
    int i, k = 0;      // 堆中元素个数的计数器初始化为0
    int v;
    KNAPNODE *xnode, *ynode, *znode;
    HEAP x, y, z, *heap;
    heap = new HEAP[n*n];        // 分配堆的存储空间
    for( i=0; i<n; i++){
       a[i].sign=i;        //记录物体的初始编号
    }
    sort(a,a+n,m);             // 对物体按照价值重量比排序
    xnode = new KNAPNODE;        // 建立父亲结点
    for( i=0; i<n; i++){           //  初始化结点
       xnode->s1[i] = false;
    }
    xnode->k = xnode->w = xnode->p = 0;
    while(xnode->k<n) {
       ynode = new KNAPNODE;     // 建立结点y
       *ynode = *xnode;         //结点x的数据复制到结点y
       ynode->s1[ynode->k] = true;     //  装入第k个物体
       ynode->w += a[ynode->k].w;     //  背包中物体重量累计
       ynode->p += a[ynode->k].p;     //  背包中物体价值累计
       ynode->k ++;               //  搜索深度++
       bound(ynode, C, a, n); //       计算结点y的上界
       y.b = ynode->b;
       y.p = ynode;
        insert(heap, y, k);        //结点y按上界的值插入堆中
       znode = new KNAPNODE;     // 建立结点z
       *znode = *xnode;          //结点x的数据复制到结点z
       znode->k++;                         //   搜索深度++
       bound(znode, C, a, n); //计算节点z的上界
       z.b = znode->b;
       z.p = znode;
       insert(heap, z, k);     //结点z按上界的值插入堆中
       delete xnode;
       x = del_top(heap, k);   //获得堆顶元素作为新的父亲结点
       xnode = x.p;
    }
    v = xnode->p;
    for( i=0; i<n; i++){     //取装入背包中物体在排序前的序号
       if(xnode->s1[i]){
           X[a[i].sign] =1 ;
       }else{
           X[a[i].sign] = 0;
       }
    }
    delete xnode;
    delete heap;
    return v;              //返回背包中物体的价值
}

/*测试以上算法的主函数*/
int main()
{
    goods b[N];
    printf("物品种数n: ");
    scanf("%d",&n);   //输入物品种数
    printf("背包容量C: ");
    scanf("%d",&C);   //输入背包容量
    for (int i=0;i<n;i++)    //输入物品i的重量w及其价值v
    {
       printf("物品%d的重量w[%d]及其价值v[%d]:  ",i+1,i+1,i+1);
       scanf("%d%d",&a[i].w,&a[i].p);
       b[i]=a[i];
    }

int sum4=KnapSack4(n,a,C,X);//调用分支限界法求0/1背包问题
    printf("分支限界法求解0/1背包问题:\nX=[ ");
    for(i=0;i<n;i++)
       cout<<X[i]<<" ";//输出所求X[n]矩阵
    printf("]  装入总价值%d\n",sum4);
    return 0;
}