实用算法的分析与程序设计——贪心算法(包含实例,代码)

包含删数问题,0-1背包和部分背包问题

贪心法也是从问题的某一个初始解出发,向给定的目标递推,但不同的是,推进的每一步不是依据某一固定的递推式,而是做一个当时看似最佳的贪心选择,不断地将问题实例归纳为更小的相似的子问题,并期望通过所做的局部最优选择产生出一个全局最优解。

这种选择未必能得出全局最优解,在下面的实例中可得到全局最优。

注意:编写这几个程序的过程发现在linux gcc编译的程序数组越界不会提示错误,也不警告,只是后面的变量参数都为0

删数问题

键盘输入一个高精度的正整数N,去掉其中任意S个数字后剩下的数字按原左右次序组成一个新的正整数,编程对给定的N和S,寻找一种方案使得剩下的数字组成的新数最小 输出应包括所去掉的数字的位置和组成的新的正整数(N不超过240位) 输入数据均不需判错

算法分析

代码如下

/* * ===================================================================================== * * Filename: delete.cc * * Description: 键盘输入一个高精度的正整数N,去掉其中任意S个数字后剩下的数字按原左右次序组成一个新的正整数,编程对给定的N和S,寻找一种方案使得剩下的数字组成的新数最小 * 输出应包括所去掉的数字的位置和组成的新的正整数(N不超过240位) * 输入数据均不需判错 * * Version: 1.0 * Created: 05/08/15 09:25:29 * Revision: none * Compiler: gcc * * Author: xiu, * Organization: * * ===================================================================================== */

#include<iostream>
#include<string>

#define SUM 256
using namespace std;

//判断字字符串是否是递增的序列,返回的是第一个不是递增序列的字符的下标
int comp(string t)
{
    int index = 0;
    while (t[index + 1] != '\0' && t[index] < t[index + 1]) 
    {
        index++;
    }
    return index;
}

//经过S次删除字符得到最小的结果
void delet(char * N, int S)
{
    cout << N << endl;
    string t(N);    

    //strcpy(t, N);
    for (int i = 0; i < S; i++) 
    {
        int index = comp( t );
        t.erase( index, 1 );
        cout<< t <<endl;
    }
}

int main()
{

    char N[SUM] = "178543";
    int S = 4;
    cout<<"input string N and S"<<endl;
    cin>>N;
    cin>>S;

    delet(N, S);
    return 0;
}

适用于贪心策略求解的大多数问题都有两个特点:

1、贪心选择性质——可通过做局部最优(贪心)选择来达到全局最优解

贪心策略通常是自顶向下做的,第一步为一个贪心选择,讲过原问题变成一个相似的但规模更小的问题,而后的每一步都是当前看似最佳的选择。这种选择可能依赖于已作出的所有选择,但不依赖有待于做的选择或子问题的解。从求解的全过程来看,每一次贪心选择都将当前问题归纳为更小的相似子问题,而每一个选择都仅作一次,无重复回溯过程,因此贪心法有较高的时间效率。

2、最优子结构——问题的最优解包含了子问题的最优解

背包问题

N件物品,第i件物品值Vi元,中Wi磅(1<=i<=n),Vi,Wi都是整数。背包只能装W磅东西。两种装包方式

每件物品或被带走或被留下,应带走哪几件东西?

允许带走某个物品的一部分,应带走哪几样东西?每件东西的重量是多少?

/* * ===================================================================================== * * Filename: package.cc * * Description: N件物品,第i件物品值Vi元,中Wi磅(1<=i<=n),Vi,Wi都是整数。背包只能装W磅东西。两种装包方式 * 每件物品或被带走或被留下,应带走哪几件东西? * 允许带走某个物品的一部分,应带走哪几样东西?每件东西的重量是多少? * * * Version: 1.0 * Created: 05/08/15 10:57:10 * Revision: none * Compiler: gcc * * Author: xiu, * Organization: * * ===================================================================================== */

#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;


#define n 5
int w[n] = { 6, 1, 2, 1, 5 };   //各物品重量
int v[n] = { 48, 7, 12, 8, 40 };    //各物品价值

const float limW = 8;       //背包容量


/* #define n 2 int w[n] = { 6, 1 }; //各物品重量 int v[n] = { 48, 7 }; //各物品价值 float limW = 8; //背包容量 */

/* #define n 7 int w[n] = { 6, 1, 2, 1, 5 , 4 , 2 }; //各物品重量 int v[n] = { 48, 7, 12, 8, 40 , 50 , 25}; //各物品价值 const float limW = 12; //背包容量 */ 


// 每件物品或被带走或被留下,仅求出最终结果
int nap(int j, float X)  //将0—j的物品,放入容积为X的背包
{

    if (j < 0)
        return (X < 0) ? -9999 : 0;

    if (X < w[j])   
    {

            //要物品j的重量大于X,则不考虑j,只考虑0—j-1
            return nap(j - 1, X);

    }

    else

    {

        int a = nap(j - 1, X);

        int b = nap(j - 1, X - w[j]) + v[j];

        if (a > b)

        {   //a>b时,即j不选择,j-1选择
            return a;

        }

        else

        {   //a<=b时,j选择,j-1是否选择待定
            return b;

        }

    }

}

//获取最大单价的物品的下标
int max1(float *every)
{
    int index = 0;

    float max = every[0];

    int i;

    for (i = 0; i < n; i++) 
    {

        if ((max - every[i]) < 0.0001) 
        {
            max = every[i];

            index = i;
        }
    }

    every[index] = 0;

    return index;
}

//允许带走某个物品的一部分,应带走哪几样东西?每件东西的重量是多少?
void nap_part()
{
    float every[n] = { 0 };     //计算单价

    int weight[n] = { 0 };      //存储所带东西的重量

    for (int i = 0; i < n; i++)

        every[i] = (float) v[i] / w[i];

    int remain = limW;


    int index = 0;

    while (remain > 0) 
    {

        index = max1(every);

        if (remain < w[index]) 
        {

            weight[index] = remain;

            remain = 0;

        } 
        else 
        {

            weight[index] = w[index];

            remain -= w[index];

        }


    }

    cout<<"下标\t" << "重量\t" << "单价" <<endl;

    for (int ii = 0; ii < n; ii++)

        cout << ii << " \t" << weight[ii] << " \t" << (float) v[ii] / w[ii] << endl;
}


int main() 
{

    //cout << nap(n - 1, limW) << endl;
    nap_part();
    return 0;

}


你可能感兴趣的:(贪心算法,部分背包,0-1背包)