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;
}