动规(13)-数据包的调度机制&山区建小学(试改成轮换数组)

Posted H_Cisco

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动规(13)-数据包的调度机制&山区建小学(试改成轮换数组)相关的知识,希望对你有一定的参考价值。

目录

一、数据包的调度机制

二、山区建小学(试改成轮换数组)


一、数据包的调度机制

描述

随着 Internet的迅猛发展,多媒体技术和电子商务应用日益广泛,Internet上的服务质量

(QoS,Qualityof Service)问题已越来越受到重视。网络中采用的数据包调度机制与网络的服务质量 QoS 有着密切的关系。研究表明传统的基于队列的调度机制已不能满足网络服务质量QoS 的需求。服务质量 QoS 取决于数据包的延迟。每一个数据包都有一个延迟惩罚值。由于数据包承载的数据不同,不同数据包的延迟惩罚值也可能不同。此外,数据包的延迟也和它的发送顺序有关。如果一个数据包被第K个发送,假设它的延迟惩罚值是D,则这个数据包的最终延迟是 (K - 1) * D。北京大学2012 级信息学院的同学在程序设计课堂上,设计了一种新的基于栈的数据包的调度算法。同学们通过栈的先进后出(Last in First out)的原理,改变数据包的发送顺序,以减小数据包的延迟总值。给定N 个等待调度的数据包,起始这N 个数据包排成一个队列等待发送。接着,这些数据包按序进栈,调度算法可以控制数据包的出栈顺序。因此通过栈,可以将后面的数据包先于前面的数据包发送出去。请你实现一个调度算法使N 个数据包的延迟总值最小。

输入

标准的输入包含若干组测试数据。输入第一行是整数T(1 <= T <= 1000),表明有T组测试数据。紧接着有T组连续的测试。每一组测试数据的第1行是 N(N <= 100),表述数据包的个数。接着的 N 行,每一行是一个整数,第i 行表示数据包i的延迟惩罚值( <=50 )。

输出

对于每组测试数据,输出最小的延迟总值。

样例输入

1

5

5

4

3

2

2

样例输出

24

#include <iostream>
using namespace std;
int n, k, t, ans;
int v[105], sum[105], f[105][105];
int main()

	cin >> t;
	while (t--)
	
		cin >> n;
		for (int i = 1; i <= n; i++)
			cin >> v[i], sum[i] = sum[i - 1] + v[i];
		for (int len = 2; len <= n; len++)
			for (int i = 1; i + len - 1 <= n; i++)
			
				f[i][len] = 0x7fffffff;
				for (int k = i; k <= i + len - 1; k++)
					f[i][len] = min(f[i][len], f[i][k - i] + v[k] * (len - 1) + f[k + 1][i + len - k - 1] + (sum[i + len - 1] - sum[k]) * (k - i));
								 //对于进栈的三段,出栈有132、123、312、321以上四种合并都包括,上面是132形式!
		cout << f[1][n] << endl; // 231这种形式在栈中不可能出现
	
	return 0; // 3  19  6  7结果为19

题解

     由于是栈,由栈的特点我们可以看出如果在某个区间中最后一个出栈的元素为k,那么必然是它前面的元素进来全部出去(或者不进来直接出),k进栈,然后后面的元素再进栈,出栈,k出栈。
首先解释预处理部分,常见的区间dp预处理,前缀和循环部分,

第一层循环,枚举区间长度,相信在区间dp中并不陌生
第二层循环,枚举区间的开始元素
第三层循环,枚举该区间内所有可能最后一个出栈的元素状态数组,f[i][len]代表以i下标为开头,len为长度的一个区间的最小值状态转移方程:由于k为最后一个出栈的元素,那么f[i][len]=f[i][k-i]+C[k]+f[k+1][i+len-1];由dp特点我们可以得到,f[i][k-i]我们是已经计算过的,直接加就好了。

C[k]是什么呢?C[k]代表k元素的延迟值,由于k是最后一个出栈的,那么在这个区间里C[k]=v[k]*(len-1);那么后面的同理加上f[k+1][i+len-k-1](即后半部分的延迟最小值)。
此时我们又遇到一个问题,我们并不能确定该区间是否为第一个进行操作的,怎么办呢?

前缀和!它们的延迟值最终答案只要再加上该区间所有元素和S*p,(p为区间在整个序列的相对位置)。S即为(sum[i+len-1]-sum[k]),p即为(k-i);
特别要注意的是,f[i][len]一开始的赋值要尽可能大,不够大的话很容易就出错了= =....

二、山区建小学(试改成轮换数组)

描述

政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m。为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 )。请根据给定的m、n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。

输入

第1行为m和n,其间用空格间隔
第2行为(m-1) 个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。
例如
10 3
2 4 6 5 2 4 3 1 3
表示在10个村庄建3所学校。第1个村庄与第2个村庄距离为2,第2个村庄与第3个村庄距离为4,第3个村庄与第4个村庄距离为6,...,第9个村庄到第10个村庄的距离为3。

输出

各村庄到最近学校的距离之和的最小值。

样例输入

10 2

3 1 3 1 1 1 1 1 3

样例输出

18

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m, x;
int dp[501][501], s[501], sum[501][501];
int main()

	scanf("%d%d", &n, &m);
	memset(dp, 0x7f, sizeof(dp));
	for (int i = 2; i <= n; i++)
	
		scanf("%d", &s[i]);
		s[i] = s[i - 1] + s[i];
	 //前缀和
	for (int i = 1; i < n; i++)
		for (int j = i + 1; j <= n; j++)
			sum[i][j] = sum[i][j - 1] + s[j] - s[(i + j) / 2]; // c处理出任意两点间建一所小学所需路程和(中点原理)
	for (int i = 1; i <= n; i++)
		dp[1][i] = sum[1][i];
	for (int k = 2; k <= m; k++)
		for (int i = k; i <= n; i++)
			for (int j = k - 1; j < i; j++)
				dp[k][i] = min(dp[k][i], sum[j + 1][i] + dp[k - 1][j]);
	printf("%d\\n", dp[m][n]); //最后区间dp
	return 0;

以上是关于动规(13)-数据包的调度机制&山区建小学(试改成轮换数组)的主要内容,如果未能解决你的问题,请参考以下文章

动规(13)-数据包的调度机制&山区建小学(试改成轮换数组)

7624:山区建小学

P4677 山区建小学|区间dp

山区建小学

山区建小学 (动态规划)

openjudge7624 山区建小学