基础算法之贪心法1

来源:互联网 发布:移动数据采集器 编辑:程序博客网 时间:2024/05/14 17:17

1.2贪心法(1)

声明:本分类中的所有博文(包括此篇博文),均为本人在学习《实用算法分析与程序设计》时所作的笔记。其中的例子全引用自《实用算法分析与程序设计》。C++代码为个人原创,转载请注明出处。

在某些情况下局部最优选择能得出全局最优解。如下。

例1.删数问题

int main(){char data[256];cout<<"please input the number"<<endl;cin>>data;int n;cout<<"please input the number of char you want to delete."<<endl;cin>>n;                    //输入删除的数字数int i,j,p,q;               //循环变量 int max;                   //记录每次删除的数字的下标for(i=1;i<=n;i++){max=0;for(j=1;j<strlen(data);j++)     //从高到底寻找递减区间,如果没有则是最后一个{if(data[j]>=data[max])max=j;else break;}if(max==0){for(p=1;p<strlen(data);p++) if(data[p]!='0')break;for(q=p;q<strlen(data);q++){data[q-p]=data[q];}data[q-p]='\0';}else{for(q=max+1;q<strlen(data);q++){data[q-1]=data[q];}data[q-1]='\0';}}cout<<data<<endl;return 0;}

例2.背包问题

     0-1背包

比如有5个物品 重量分别为weight[6] {2,4,3,1,5}  (weight[0]不使用)

                                   价值分别为value[6] {4,6,2,2,9}  (value[0]不使用)

要求总重量不超过12。

我们先建立一个数组,array[6][12]

array[m][n]表示标号为m及标号大于m的物品允许放入背包中,如果重量不超过n,那么最好的状况总价值是多少。

如array[3][7]表示3号4号5号允许放入背包中,重量不超过8时,最好状况总价值死多少。观察得最好是把4号和5号放进去,总重量6(小于7),总价值应该是11。所以array[3][7]=11;

有个规律,array[m][n]=max{array[m+1][n], array[m+1][n-weight[m]] +value[m]}即考虑m号物品要不要放进去,不放进去的状况总价值=array[m+1][n],放进去总价值=array[m+1][n-weight[m]] +value[m]。


#include <iostream>#include <stdio.h>#include<math.h>#include <string.h>#include "stdlib.h"using namespace std;typedef struct{    int object;    int weight;    int value;}KnapSack;KnapSack * knapSack;int num;int container;int **array=NULL;void Create_KnapSack()       //建立物品{    char c;    cout<<"input the number of objects"<<endl;    cin>>num;    knapSack=new KnapSack[num+1];    cout<<"input weight and value of "<<num<<" objects,like 1:4 10"<<endl;    for(int i=1;i<=num;i++)    {        cin>>knapSack[i].object>>c>>knapSack[i].weight>>knapSack[i].value;    }    cout<<"input the volume of the knapsack:"<<endl;    cin>>container;}void Resolve_KnapSack()    //解决背包问题{    array=(int **)malloc((num+1)*sizeof(int *));//要加#include “stdlib.h”;不然会提示malloc在此作用域中尚未声明    for(int i=0;i<=num;i++)    {        array[i]=(int *)malloc((container+1)*sizeof(int));    }    for(int j=0;j<=container;j++)    {        array[num][j]=(j>=knapSack[num].weight)?knapSack[num].value:0;    }    for(int m=num-1;m>0;m--)    {        for(int n=0;n<=container;n++)        {            if(n>=knapSack[m].weight&&array[m+1][n]<=array[m+1][n-knapSack[m].weight]+knapSack[m].value)            array[m][n]=array[m+1][n-knapSack[m].weight]+knapSack[m].value;            else            array[m][n]=array[m+1][n];        }    }}bool * Trace_back()           //回溯,找哪些物品被放进背包中了{    int c=container;    bool *used;    used=(bool *)malloc((num+1)*sizeof(bool));    for(int i=1;i<num;i++)    {        if(array[i][c]==array[i+1][c])        used[i]=0;        else        {            used[i]=1;            c-=knapSack[i].weight;        }    }    used[num]=(c==knapSack[num].weight)?1:0;    return used;}void Print_KnapSack(bool *used)          //打印背包中的物品{    cout<<"the objects used as follows:"<<endl;    for(int i=1;i<=num;i++)    {        if(used[i])        cout<<knapSack[i].object<<": "<<knapSack[i].weight<<"  "<<knapSack[i].value<<endl;    }}int main(){    bool * used;    Create_KnapSack();    Resolve_KnapSack();    used=Trace_back();    Print_KnapSack(used);return 0;}

完全背包问题

基本思路
完全背包问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:

array[m][n]=max{array[m+1][n], array[m+1][n-k*weight[m]] +k*value[m]} (0<=k*weight[m]<=n )

对其可以进行优化,把它变为一维的。

for i: container...1

array[n]=max{array[n],array[n-weight[i]]+value[i]}

就是相当于把0-1背包化成一维的,每次都覆盖前面那次的结果。

#include <iostream>#include <stdio.h>#include<math.h>#include <string.h>#include "stdlib.h"using namespace std;typedef struct{    int object;    int weight;    int value;}KnapSack;KnapSack * knapSack;int num;int container;int *array=NULL;void Create_KnapSack()       //建立物品{    char c;    cout<<"input the number of objects"<<endl;    cin>>num;    knapSack=new KnapSack[num+1];    cout<<"input weight and value of "<<num<<" objects,like 1:4 10"<<endl;    for(int i=1;i<=num;i++)    {        cin>>knapSack[i].object>>c>>knapSack[i].weight>>knapSack[i].value;    }    cout<<"input the volume of the knapsack:"<<endl;    cin>>container;}void Resolve_KnapSack()    //解决背包问题{    array=(int *)malloc((container+1)*sizeof(int));    for(int i=0;i<=container;i++)    {        if(i<knapSack[num].weight)array[i]=0;        else array[i]=(i/knapSack[num].weight)*knapSack[num].value;    }    for(int i=1;i<=container;i++)cout<<"  "<<array[i];    cout<<endl;    for(int i=num-1;i>=1;i--)    {        for(int j=1;j<=container;j++)        {            if(j>=knapSack[i].weight)            {                int t=array[j-knapSack[i].weight]+knapSack[i].value;                array[j]=(t>=array[j])?t:array[j];            }        }        for(int i=1;i<=container;i++)cout<<"  "<<array[i];        cout<<endl;    }}void Trace_back(int *used)           //回溯,找哪些物品被放进背包中了{    int c=container;    memset(used,0,(num+1)*sizeof(int));    for(int i=num;i>=1;i--)    {        for(int j=i;j>=1;j--)        {            if(array[c]==(array[c-knapSack[j].weight]+knapSack[j].value))            {                used[j]++;                c=c-j;                break;            }        }    }    return ;}int main(){    freopen("input.txt","r",stdin);    int * used;    used=(int *)malloc((num+1)*sizeof(int));    Create_KnapSack();    Resolve_KnapSack();    cout<<"The max value is: "<<array[container]<<endl;    Trace_back(used);    cout<<"name:   ";    for(int i=1;i<=num;i++)cout<<"  "<<i;    cout<<endl;    cout<<"numbers:";    for(int i=1;i<=num;i++)cout<<"  "<<used[i];    fclose(stdin);return 0;}

部分背包问题

问题描述:n件物品,第i件物品价值 vi 元,重wi 磅。希望用 W磅的背包 拿走最重的物品。第i件物品可以都拿走,也可以拿走一部分。(物品可以分割所以称为部分背包)

按照物品价值重量比,每次选择价值重量比最高的物体放入,可保证放入的价值一定最大。

#include <iostream>#include <stdio.h>#include<math.h>#include <string.h>#include "stdlib.h"using namespace std;typedef struct{    int object;    int weight;    int value;}KnapSack;KnapSack * knapSack;int num;int container;int *array=NULL;void Create_KnapSack()       //建立物品{    char c;    cout<<"input the number of objects"<<endl;    cin>>num;    knapSack=new KnapSack[num+1];    cout<<"input weight and value of "<<num<<" objects,like 1:4 10"<<endl;    for(int i=1;i<=num;i++)    {        cin>>knapSack[i].object>>c>>knapSack[i].weight>>knapSack[i].value;    }    cout<<"input the volume of the knapsack:"<<endl;    cin>>container;}void Sort_KnapSack(){    int i,j;    float a1,a2;    int temp;    for(i=1;i<=num;i++)    {        for(j=1;j<=num-i;j++)        {            a1=((float)knapSack[j].value)/((float)knapSack[j].weight);            a2=((float)knapSack[j+1].value)/((float)knapSack[j+1].weight);            if(a2>a1)            {                temp=knapSack[j].value;                knapSack[j].value=knapSack[j+1].value;                knapSack[j+1].value=temp;                temp=knapSack[j].weight;                knapSack[j].weight=knapSack[j+1].weight;                knapSack[j+1].weight=temp;                temp=knapSack[j].object;                knapSack[j].object=knapSack[j+1].object;                knapSack[j+1].object=temp;            }        }    }}float Resolve_KnapSack(int *used)    //解决背包问题{    int left=container;    float value=0;    for(int i=1;i<=num;i++)    {        if(knapSack[i].weight<left)        {            used[knapSack[i].object]=knapSack[i].weight;            left-=knapSack[i].weight;            value+=knapSack[i].value;            if(left==0)break;        }else        {            used[knapSack[i].object]=left;            left=0;            value+=((float)knapSack[i].value)/((float)knapSack[i].weight)*((float)left);            break;        }    }    return value;}int main(){    Create_KnapSack();    Sort_KnapSack();    int *used=new int[num+1];    float maxValue;    maxValue=Resolve_KnapSack(used);    int i;    cout<<maxValue<<endl;    for(i=1;i<=num;i++)    {        cout<<i<<":  "<<used[i]<<endl;    }return 0;}