TCO2012Round1B-2-FoxAndDoraemon

来源:互联网 发布:郑州财经学院网络管 编辑:程序博客网 时间:2024/06/04 14:23
zz:http://www.strongczq.com/2012/04/tco2012round1b-2-foxanddoraemon.html

题目原文:
http://community.topcoder.com/stat?c=problem_statement&pm=11860&rd=15091

题目大意:
     有一只狐狸需要完成一系列任务,int[] workCost表示完成每个任务需要的时间。狐狸可以进行分裂,每只狐狸经过splitCost时间进行分裂后会产生一只新的狐狸。每只狐狸只愿意进行一项任务。分裂的时候不可以执行任务,但是对执行任务和进行分裂的次序没有要求。问最短可以在多少时间内完成所有任务。
     数据规模:任务个数为[1,50],每个任务的执行时间为[1,3600],splitCost为[1,3600] 

思路:
     假设任务数为n,由于每只狐狸只愿完成一项任务,所有最终必然需要n只狐狸,需要进行n-1次分裂。显然一只狐狸先完成任务再分裂是完全没有必要的,因为如果相应的改为先分裂再完成任务最终使用时长不会更长。所以,在时间序列上,可以先进行分裂然后再完成任务。狐狸的分裂方案可以用一颗二叉树来表示,二叉树的每一个叶子节点为一只最终执行任务的狐狸,叶子节点数为n。假设已知某个case下的某个最优解决方案的分裂过程(如下左图所示的是某7个任务的情况),那么我们总是能够将二叉树重构成符合以下条件的另一个二叉树(如下右图所示):
  • 二叉树各高度叶子节点数与原二叉树相同
  • 二叉树的叶子节点从左到右按高度从大到小排序。
   
       根据以上第一个条件可知,该新二
树的分裂方案仍然可以生成最优解决方案,一种最优解决方案是:将任务按执行时间从大到小排序,然后将对应序号的任务安排给对应序号的叶子节点。所以我们可以得到一个结论:将所有任务按照执行时间从大到小排序(或者从小到大),必然存在某种分裂方案,其对应的二叉树叶子节点从左往右按序号搭配对应任务,所构成的整体方案是一个最优方案。


     根据以上分析,我们需要解决的问题是:对排好序的任务,寻找到能够使得结果最优的二叉树结构。这个问题是一个典型的动态规划问题,状态方程可以表示为f(i,j)表示只考虑编号从i到j的任务,生成一个二叉树使得所有任务完成的时间点最小,方程值为分裂+执行任务的总时间。状态转移方程为:
     f(i,j) = splitCost + min(max(f(i,i),f(i+1,j)), max(f(i,i+1,), f(i+2,j)),..., max(f(i,j-1),f(j,j)) )
即对与[i,j]区间的任务,考虑二叉树根节点的所有情况,取最优的那个。算法的时间复杂度为O(n^3)。

Java代码:
public class FoxAndDoraemon {    public int minTime( int[] workCost, int splitCost) {        int n = workCost.length ;        Arrays. sort(workCost);        int [][] dp = new int[n][n];        for (int i = 0; i < n; ++i)            dp[i][i] = workCost[i];        for (int k = 1; k < n; ++k) {            for (int s = 0; s < n; ++s)                if (s + k < n) {                    int t = s + k;                    dp[s][t] = Integer. MAX_VALUE ;                    for (int i = s; i < t; ++i) {                        dp[s][t] = Math. min(dp[s][t], splitCost + Math.max(dp[s][i], dp[i + 1][t]));                    }                }        }        return dp[0][n - 1];    }}



原创粉丝点击