[HNOI2002]Tinux系统

【题目描述】
原题又臭又长 不写了
大意:一棵有根树 每一个节点最多只能有(k)个子节点 要放(n)个文件进去 文件只能放在叶子节点里 从任意一个非叶子节点(文件夹)访问到他的第(i)个子节点需要耗费时间(p_i) 访问一个文件的时间定义为从根节点访问到该文件所处的叶子节点所需时间 求一种文件放置方法 使得依次访问每个文件花费的时间总和最小
ps 如果我讲的太过艰涩难懂 原题面在文章末尾

【输入格式】
文件的第一行为两个正整数(N,K)((1 le N le 1000, 2 le K le 150))接下来的(K)行每行有一个正整数(P_i, P_i le150)

【输出格式】
在最优存储方案下的时间总和

这题在某谷上是黑题
黑题我怎么会做呢 网上搜了一下题解的思路然后胡搞搞过了就来写Blog

首先 由于对于一个非叶子节点我们可以随便选择优先用哪个子节点 所以肯定从时间花费少的用起 所以可以先给(p)数组排序

然后此题我们可以用记忆化搜索求解实际上就是DP(f[i][j])表示 还剩(i)个文件需要安排 使用第(j)个子节点到第(k)(如果忘了(k)是什么 回去读题)个子节点(排序后的) 最优安排方案下访问这(i)个点所需的最短时间

转移 对于(dp[i][j]) 如果(i=1) 就直接把这个文件扔当前这个第(j)个子节点就行了
如果(j=1)(i>1) 那就必须在第(j)个子节点这个位置新开一个文件夹了 耗费时间就是(dp[i][1])(新文件夹从子节点1开始)(+p[i]*i*i) (p[i]*i*i)就是把这(i)个文件经过这里所需的时间给提前算进去了
对于其它情况 枚举(x)表示要放在当前的第(j)个子节点的位置或者(j)位置下面的文件夹的文件个数 (dp[i][j] = min(dp[x][1]+dp[i-x][j+1]+p[i]*x*x));

DP时可以使用一种dfs的方法

【代码】

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;

ll n, k, p[1005];
ll dp[1005][205];

int dfs(ll need, ll cur) {
    if (need == 1) {
        return dp[need][cur] = p[cur];
    } else if (cur == k) {
        return dp[need][cur] = p[cur] * need * need + dfs(need, 1);
    }
    if (dp[need][cur]) return dp[need][cur];
    dp[need][cur] = p[cur] + dfs(need - 1, cur + 1);
    for (int i = 2; i < need; i++) {
        dp[need][cur] = min(dp[need][cur], dfs(need - i, cur + 1) + dfs(i, 1) + p[cur] * i * i);
    }
    return dp[need][cur];
}

int main() {
    scanf("%lld %lld", &n, &k);
    for (int i = 1; i <= k; i++) {
        scanf("%lld", &p[i]);
    }
    sort(p + 1, p + k + 1);
    printf("%lld
", dfs(n, 1));
    return 0;
}

众所周知 黑题的代码量很小







































我就知道你会下来看题面

在dos系统诞生以前,美国曾研究出一种类似的操作系统,名为Tinux系统。但由于硬件设施的制约,Tinux系统有许多的缺点。下面就对Tinux系统作一个简单的介绍:Tinux系统是Tiger博士为美国军方研制开发的一种操作系统,该系统对文件的存储方式类似于dos系统,像一棵树一样,每一个叶子节点表示一个文件,每一个非叶子节点表示一个目录。其中定义i级子目录表示从根目录开始访问,一直访问到该子目录(不包括该子目录)需要访问的目录的个数为i的目录,所以根目录下的目录为一级子目录,其他的目录以此类推。但是在同一子目录下,受到硬件的制约Tinux系统最多只能够存储k个文件或子目录,也就是说这棵树里面的每一个非叶子节点最多只有k个子节点。这样就导致在文件数量较多的情况下,访问存储在该系统当中的文件A,往往要先访问一系列的子目录,我们称这些子目录为文件A的上级目录。例如下面这一个例子:Root A1 A2 A3 A4 A4A1 A4A2 A4A2A1 A4A2A2 A4A3当我们要访问文件A4A2A1时就必须先访问它的上级目录:一级子目录A4和二级子目录A4A2。Tinux系统在存储文件时,给每一个子目录都分配了k个指针,分别指向存放在该目录下的每一个文件和每一个目录,因此对文件的访问实质上就是对指针的访问。但是由于硬件原因,这k个指针不尽相同,因此访问它们的时间也不同,访问第i个指针所耗费的时间为 。但是对于两个不同的子目录(不管它们各自属于哪一级目录)而言它们各自所拥有的k个指针是相同的。Tinux系统最大的缺点是访问一个目录时,必须把该目录下所有的文件读入到内存当中来,这些文件包括在其各级子目录当中的文件,例如上面那一个例子,访问A4那一个目录,就必须把A4A1,A4A2A1,A4A2A2,A4A3这四个文件都读入到内存当中来,访问一个目录所需要的时间为 (x表示该目录及其各级子目录下文件的个数, 表示指向该目录的指针的访问时间)。因此根据上面介绍的访问方法,单独访问一个文件所需要的总时间为访问其所有上级目录(不包括根目录)所需要的时间与访问指向该文件的指针所需要的时间的和,例如上面那一个例子,访问文件A4A2A1需要的时间=访问目录A4的时间+访问目录A4A2的时间+访问指向文件A4A2A1的指针需要的时间。现在,tiger博士准备将n个文件存储到一个空的Tinux系统当中,希望你帮助他设计一个程序找到一种最优的存储方法,使得单独访问这n个文件所需要的时间总和最小。

原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM12.html