6046:数据包的调度机制【区间dp】

题目链接http://noi.openjudge.cn/ch0206/6046/

描述

随着 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

查看

# 结果 时间
3 Accepted 08-18
2 Wrong Answer 08-18
1 Wrong Answer

06-12

这道题目积压的时间挺长的。第一眼看这道题目我是懵逼的。我尝试了贪心的做法,发现是错的。因为这里有栈的存在,所以数据包不可能以任意顺序出栈。之后便在网上查找各种资料。这是一个区间动态规划问题。这个名称很高大上。。我看了很久才看明白这是怎么一回事。

考虑栈的操作特点是先进后出。此题中的数据包排成队列依次进栈。最后一个出栈的数据包是关键,它将整个过程分为两段,它之前的数据包和它之后的数据包。因此可以猜测子问题如何分解。直接上状态转移方程:

dp[ i ][ j ]表示第 i 个数据包到第 j 个数据包的最小延迟

dp[ i ][ j ]=min(dp[ i ][ j ],
dp[ i ][ k-1 ]+dp[ k+1 ][ j ]+penalt[ k ]* ( l-1 )+(sum[ j ]-sum[ k ])*(k-i));( i<=k<=j )

第k个数据包最后出栈

dp[ i ][ k-1 ]表示之前的数据包的最小延迟

dp[ k+1 ][ j ]表示之后数据包的最小延迟

penalt[ k ]* ( l-1 )第k个数据包的最小延迟

(sum[ j ]-sum[ k ])*(k-i))后半段的数据包由于是在前半段数据包之后发送所以他们的发送次序是从k-i+1开始的,所以加上这个差值。

枚举的时候先枚举区间的长度,然后枚举区间的起点,因为当前的区间总是依赖更短的区间进行更新。这样枚举满足由已知推未知

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#define DEBUG(x) cout<<#x<<" = "<<x<<endl
using namespace std;
const int MAXN=1e2+10;
const int INF=0x3f3f3f3f;
int T,N;
int penalt[MAXN];
int sum[MAXN];
int dp[MAXN][MAXN];
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        memset(sum,0,sizeof(sum));
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=N ;i++ ){
            scanf("%d",&penalt[i]);
            sum[i]=sum[i-1]+penalt[i];
        }
        for(int l=1;l<=N ;l++ ){
            for(int i=1;i<=N-l+1 ;i++ ){
                int j=l+i-1;
                dp[i][j]=INF;
                for(int k=i;k<=j ;k++ ){
                    dp[i][j]=min(dp[i][j],
                                 dp[i][k-1]+dp[k+1][j]+penalt[k]*(l-1)+(sum[j]-sum[k])*(k-i));
                }
            }
        }
        printf("%d
",dp[1][N]);
    }
}

学习资料https://blog.csdn.net/qq_16964363/article/details/79205916

原文地址:https://www.cnblogs.com/MalcolmMeng/p/9496200.html