包含删数问题,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;
}