基础算法之贪心法1

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值