2

一段时间以来,我一直在尝试解决这个 TopCoder 问题,但我无法提出基于 DP 的解决方案来解决这个问题(如下所示)。我还找到了其他人对该问题的解决方案(也在下面给出),但我什至无法理解。

谁能帮我解决这里的问题?我不明白什么思路会导致这个解决方案?如何在我的脑海中建立递归关系?我完全不知道如何解决这个问题,或者编写该解决方案的人是如何编写它的。

PS:我知道TopCoder 有问题的社论,但是这个还没有发布。我不知道为什么。

这就是问题所在

Fox Ciel 有很多功课要做。作业由一些相互独立的任务组成。不同的任务可能需要不同的时间来完成。您将获得一个 int[] workCost。对于每个 i,第 i 个任务需要 workCost[i] 秒才能完成。她想参加一个聚会和认识她的朋友,因此她想尽快完成所有任务。

主要的问题是,包括夏尔在内的所有狐狸都非常讨厌做作业。每只狐狸只愿意做其中一项任务。幸运的是,来自 22 世纪的机器猫哆啦A梦给了 Fox Ciel 一把分裂锤:一个可以将任何狐狸分成两只狐狸的魔法小工具。

你得到一个 int splitCost。在狐狸身上使用劈锤是瞬间的。一旦在狐狸身上使用锤子,狐狸就会开始分裂。splitCost 秒后,她会变成两只狐狸——原来的狐狸和另一只全新的狐狸。狐狸在劈叉时,不能再用锤子打她。

一项任务的工作不能被打断:一旦狐狸开始执行一项任务,她就必须完成它。不允许多只狐狸在同一任务上合作。狐狸在使用锤子被劈开时无法完成任务。可以多次拆分同一只狐狸。在狐狸完成其中一项任务之前和之后都可以分裂狐狸。

计算并返回狐狸可以解决所有任务的最短时间。

这是解决方案

1:    
2:  const int maxN = 55;  
3:  int dp[maxN][maxN*2];  
4:  int N;  
5:  int splitC;  
6:  vector<int> workC;  
7:    
8:  int rec(int,int);  
9:  int FoxAndDoraemon::minTime(vector <int> workCost, int splitCost) {  
10:      
11:    sort(workCost.begin(), workCost.end());  
12:    N = workCost.size();  
13:    splitC = splitCost;  
14:    workC = workCost;  
15:       memset(dp, -1, sizeof(dp));  
16:      
17:    return rec(N-1, 1);  
18:  }  
19:    
20:  int rec(int jobs, int fox)  
21:  {  
22:    if(jobs == -1) return 0;  
23:      
24:    int& val = dp[jobs][fox];  
25:    if(val != -1) return val;  
26:    val = 0;  
27:      
28:    if( (jobs+1) <= fox) val = max(workC[jobs] , rec(jobs-1, fox-1));  
29:    else  
30:    {  
31:      //split fox  
32:      val = splitC + rec(jobs, fox + 1);  
33:        
34:      if( !(fox == 1 && jobs > 0) )  
35:        val = min(val, max(workC[jobs], rec(jobs-1, fox-1)));  
36:    }  
37:    return val;  
38:  }  
39:    
4

2 回答 2

1

DP 问题通常需要你做几个例子,而要擅长它的唯一方法就是练习。尝试解决 DP 中的一些标准问题类型,如最长递增子序列、背包、硬币变化、矩阵乘法、TSP 等。尝试这些类型的变体。

至于上面的问题,有几点需要注意:

  • 你需要 N 只狐狸来完成 N 项任务(1 只狐狸只能完成 1 项任务)。因此,如果您已经克隆了 N 只狐狸,则无需再创建。而且,如果你有多个任务,你必须分裂第一只狐狸。
  • 每只狐狸你可以做两件事
    • 拆分它,然后计算所用的最短时间
    • 不要拆分,而是执行当前任务,并计算少一只狐狸执行剩余任务所需的时间。
      • 请注意,如果您有超过 1 只狐狸(或 1 只狐狸有 1 个任务),您只能选择不拆分。

这应该给你一个问题的想法。我还没有彻底分析问题,但递归似乎并没有创建重叠调用,即如果我有 3 个任务和 2 个狐狸,我只调用该状态一次,不再调用。因此,该解决方案是常规递归解决方案,而不是 DP。

于 2012-04-28T10:20:13.963 回答
0

该社论现已在 TopCoder 网站上发布。您可以在那里查看!

于 2012-06-20T20:23:48.240 回答