磁盘最优存储问题【深度优先搜索算法】

题目描述
设有n 个程序{1,2,…, n }要存放在长度为L的磁带上。程序i存放在磁带上的长度是Li, 1<= i<= n。这n 个程序的读取概率分别是p1,p2,...,pn,且pi+p2+...+pn = 1。如果将这n 个程序按 i1,i2,....,in 的次序存放,则读取程序ir 所需的时间tr=c*(Pi1*Li2+Pi2*Li2+...+Pir*Lir)。这n 个程序的平均读取 时间为t1+t2+...+tn。 磁带最优存储问题要求确定这n 个程序在磁带上的一个存储次序,使平均读取时间达到 最小。试设计一个解此问题的算法,并分析算法的正确性和计算复杂性。 编程任务: 对于给定的n个程序存放在磁带上的长度和读取概率,编程计算n个程序的最优存储方 案。
输入
由文件input.txt给出输入数据。第一行是正整数n,表示文件个数。接下来的n行中, 
每行有2 个正整数a 和b,分别表示程序存放在磁带上的长度和读取概率。实际上第k个程 
序的读取概率ak/(a1+a2+...+an)。对所有输入均假定c=1。
输出:
输出一个实数,保留1位小数,表示计算出的最小平均读取时间。

#include<iostream>
#include<limits.h>
#include<vector>
using namespace std;
int answernum = 0;
float answer=0;
float arr1[] = { 33,55,22,11,9 };
vector<float>v;
float smallest= INT_MAX;
void  minStorage(int n, int a[]) {
	int sum = 0;
	for (int i = 0; i < n; i++) {
		sum += arr1[a[i]];
	}
	float result = 0;
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {    //从磁道0-n-1。计算它们的磁道间的检索时间
			result += (arr1[a[i]] * 1.0 / sum) * (arr1[a[j]] * 1.0 / sum) * (j - i);
		}
	}
	answernum++;
	if (result < smallest)
	{
		smallest = result;
		if (!v.empty())
			v.clear();
		for (int i = 0; i < n; i++)
			v.push_back(arr1[a[i]]);
	}
}
void swap(int arr[], int i, int j)//交换值
{
	float tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}
float Pruning_Function(int n,int a[])
{
	int sum = 0;
	for (int i = 0; i < n; i++) {
		sum += arr1[a[i]];
	}
	float result = 0;
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {    //从磁道0-n-1。计算它们的磁道间的检索时间
			result += (arr1[a[i]] * 1.0 / sum) * (arr1[a[j]] * 1.0 / sum) * (j - i);
		}
	}
	return result;
}
void func(int arr[], int i, int length)
{
	if (i == length)//跑到一个叶子节点上了
	{
		minStorage(length,arr);
	}
	else
	{
		//生成当前i节点的所有孩子节点
		for (int k = i; k < length; ++k)
		{
			swap(arr, i, k);//当前i位置的元素和后边所有元素交换
			
			if(Pruning_Function(i+1,arr)<smallest)
			func(arr, i + 1, length);//遍历i的一个孩子
		
			swap(arr, i, k);
			//回溯到父节点,一定要再交换回来,因为生成新的孩子是基于父节点进行元素的交换
		}
	}
}
int main()
{
	int arr[] = { 0,1,2,3,4};
	
	int length = sizeof(arr) / sizeof(arr[0]);
	func(arr, 0, length);
	cout << smallest<<endl;
	cout << answernum << endl;
	for (auto i = v.begin(); i != v.end(); i++)
	{
		cout << *i << " ";
	}
	return 0;
}

这个题目可以用贪心算法解,我浏览了网上的大部分代码,发现几乎都是使用贪心算法去接,但我在拿到这道题目的时候首先想到的是用深度优先搜说去遍历他,这个地方对深度优先搜索的框架不在赘述,我直接分享我设计的剪枝函数:

float Pruning_Function(int n,int a[])
{
	int sum = 0;
	for (int i = 0; i < n; i++) {
		sum += arr1[a[i]];
	}
	float result = 0;
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {    //从磁道0-n-1。计算它们的磁道间的检索时间
			result += (arr1[a[i]] * 1.0 / sum) * (arr1[a[j]] * 1.0 / sum) * (j - i);
		}
	}
	return result;
}

在未剪枝前深度优先搜索一共暴力遍历了:120次

而在采用了设计的剪枝函数之后一共遍历了:5次

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值