具体问题
★问题描述:
设有n个程序{1,2,…,n}要存放在长度为L的磁带上。程序i存放在磁带上的长度是li,1<=i<=n.
程序存储问题要求确定这n个程序在磁带上的一个存储方案,使得能够在磁带上存储尽可能多的程序。在保证存储最多程序的前提下还要求磁带的利用率最大。
编程任务:
★算法设计:
对于给定的n个程序存放在磁带上的长度,编程计算磁带上最多可以存储的程序数和占用磁带的长度。
★数据输入:
由文件input.txt给出输入数据。第1行是2个正整数,分别表示文件个数 n 和磁带的长度 L 接下来的1行中,有 n 个正整数,表示程序存放在磁带上的长度。
★结果输出:
将计算的最多可以存储的程序数和占用磁带的长度及存放在磁带上的每个程序的长度输出到文件 output.txt。第1行输出最多可以存储的程序数和占用磁带的长度;第2行输出存放在磁带上的每个程序的长度。
输入文件示例
Input.txt
9 50
2 3 13 8 80 20 21 22 23
输出文件示例
output.txt
5 49
2 3 13 8 23
解题思路
根据题目要求,这是一个典型的空间利用问题,类似于0-1背包问题,所以使用贪心算法是能够解决的。题目要求存放程序最多的同时磁带利用率最大,存放程序个数最多显然是尽可能多存放占用长度小的程序。所以不难想出一个策略,将程序占用长度从小到大排列,优先存放小的,直到再放入下一个时长度超出,此时得到的存放程序个数显然是最多的,在这个个数条件下要使磁带利用率最大,应该使此时所得程序组的最后一个被替换成占用长度更大的程序,这样就得到了最大占用长度程序组。
源代码
#include<iostream>
#include<algorithm>
#include<fstream>
#define MAX 256
using namespace std;
int a[MAX];//全局变量数组
void input()
{
int i;
ifstream fin("input.txt");
while(!fin.eof())
{
fin>>a[i++];//读取文件中数据,以数组形式存放
}
fin.close();//关闭原文件
}
void output(int n,int m,int sum,int num,int x[])
{
int i,j;
ofstream out("output.txt");
if(out.is_open())
{
out<<n<<" "<<sum<<endl;//写入最多可以存储的程序数和占用磁带的长度
for(i=2;i<2+num;i++)
{
for(j=0;j<n;j++)
{
if(a[i]==x[j])
{
out<<a[i]<<" ";//写入内容
x[j]=-1;//标记已输出的存放程序,防止输出重复
break; //找到一个就退出一个循环
}
}
}
out.close(); //关闭输出文件
}
cout<<"运行成功!"<<endl;
}
//核心运算代码块(贪心算法)
void Deal(int x[])
{
int num,container;
int i,k,m,n;//m为单个程序最大占用磁带长度,n为最大可存储程序个数
num=x[0]; //标记程序个数
container=x[1]; //标记最大空间
int b[MAX],j=0,sum=0;//初始化sum
for(i=2;i<2+num;i++)
{
b[j++]=a[i];//将a数组导入到b数组,导入注意数组下标从2开始才是各程序占用长度
sum+=a[i];//计算长度总和,避免程序陷入死循环
}
sort(b,b+num);//从小到大排列b数组
if(sum<container)
cout<<"数据错误或异常,请检查原始数据,已停止运算!"<<endl;//磁带长度大于所有程序占用总和,没有计算必要
else if(b[0]>container)//当最小占用长度大于可用长度时直返回错误
cout<<"数据错误或异常,请检查原始数据,已停止运算!"<<endl;
else{
sum=0;
for(k=0;k<num;k++)
{
sum+=b[k];//从小累加,使放入程序数最多即尽可能多放占用空间小的
if(sum>container)
{
sum=sum-b[k]-b[k-1];//去掉最后一个以及新加入的程序
n=k;//可执行程序个数(实际是最终个数)
break;
}
}
for(k=n-1;k<num;k++)//将最后一个替换成尽可能长度占用大的程序
{
if(b[k]+sum>container)//寻找越界条件,当放入b[k]超出时取前一个
{
m=b[k-1];//标记最后一个最大可存储程序占用空间
sum+=b[k-1];//得到最大占用磁带长度
break;
}
}
b[n-1]=m;//将数组b第n个元素变成m
output(n,m,sum,num,b);//调用output,生成输出文件
}
}
int main()
{
input();//读取原文件
Deal(a);//处理运算
}
运行结果
结语
制作不易,感谢支持!