动态编程/组合没有重复和顺序并不重要

时间:2014-06-22 12:29:59

标签: java algorithm combinations dynamic-programming combinatorics

假设我们有一些长度为L的铁路。我们需要在这条铁路的第一公里和最后一公里之间设置K个服务站。 0和L km的服务站已经免费建造。给出了在这条铁路每公里处建立一个服务站的价格以及计算给定长度铁路的服务价格的等式。

例如,我们有4公里铁路,并获得在铁路第n公里建一个车站的价格清单:

5 22 13

我们也有站点之间的服务等式 - PRICE(len) = 2 * len*len + 3*len.

因此,我们需要建立 1 电台,我们可以这样做:

1 km - 建筑费用 5 ,PRICE(1)= 5 (服务0至1公里)+ PRiCE (3)= 27(从1到4 km服务)=> 37

第2公里 - 建筑成本 22 ,PRICE(2)= 14 (服务从0到2公里)+ PRiCE (2)= 14(服务从2到4公里)=> 50

第3公里 - 建筑成本 13 且价格<3> = 27 (服务从0到3公里)+ PRiCE (1)= 5(服务从3到4公里)=&gt; 69

最佳选择是在第一公里建立 1 电台。

如果我们需要建立 2 电台,该怎么办?

 |S|_|_|_|F|

 |S|1|2|_|F|  5+22+PRICE(1)+PRICE(1)+PRICE(2) = 5 + 22 + 5 + 5 + 14 = 51 
 |S|1|_|3|F|  5+13+PRICE(1)+PRICE(2)+PRICE(1) = 5 + 13 + 5 + 14 + 5 = 42
 |S|_|2|3|F|  22+13+PRICE(2)+PRICE(1)+PRICE(1) = 22 + 13 + 14 + 5 + 5 = 59

所以,最好的方法是在第一和第三公里处放置两​​个车站。

我的任务是找到给定长度的最低价格,要建造的车站数量,在特定公里和等式上建站的价格。

我的想法是计算len表以了解维持特定长度的成本。对于给定的示例,它是表:

+------+------+------+------+
| idx0 | idx1 | idx2 | idx3 |
+------+------+------+------+
|    0 |    5 |   14 |   27 |
+------+------+------+------+

然后我用成本计算表格,以便在特定公里上建立任意两个站点:

╔══════╦══════╦══════╦══════╦══════╗
║      ║ idx0 ║ idx1 ║ idx2 ║ idx3 ║
╠══════╬══════╬══════╬══════╬══════╣
║ idx0 ║      ║      ║      ║      ║
║ idx1 ║      ║    5 ║   32 ║   32 ║
║ idx2 ║      ║      ║   22 ║   40 ║
║ idx3 ║      ║      ║      ║   13 ║
╚══════╩══════╩══════╩══════╩══════╝

那么,我只是创建递归并通过这样做:

 public static void recur(int cost, int level, int idx) {
        if (level == 0) {
            if (min > cost + len[delka - idx]) {
                min = cost + len[delka - idx];
                System.out.println(min);
            }

        }
        if (level > 0 && cost < min) {
            for (int i = idx; i <= delka - level; i++) {
                recur(cost + d[idx][i], level - 1, i);                
        }
    }

我开始用0成本调用它,level是要建立的站点数,idx是指向最后一个建站的指针。

最大的问题是,例如对于L = 200和50个站点,有4.538583779232459e + 47种组合,我不认为我在每个组合中做得很好。当然我剪了一些cost < min,但它仍然超级慢,我想我只是缺少一些东西。

我觉得我可以将其分解为子问题。

捷克语中的原始问题:https://cw.felk.cvut.cz/courses/a4b33alg/task.php?task=servis

1 个答案:

答案 0 :(得分:1)

首先,请注意,对于任何位置x,如果我们已经计算了将最后一个站点放在yth km上的结果,则y&lt; x,x或右边的结果将不依赖于y之前的台站选择。所以DP解决方案的状态将是[KM] [position_of_last_station] [station_already_built]

示例代码如下:

int memo[MAX_KM][MAX_KM][MAX_STATION];
bool seen[MAX_KM][MAX_KM][MAX_STATION]; // if seen[km][pos_of_last_station][station_remaining] is true 
                                         // then this subproblem has already been solved. No need to solve it again

int dp(int KM, int pos_of_last_station, int station_remaining) {
    if(KM == MAX_KM + 1) {
        // reached the end
        int len = (MAX_KM - pos_of_last_station);
        return 2 * len * len + 3 * len;
    }

    if(seen[KM][pos_of_last_station][station_remaining]) {
        // this sub problem has already been solved
        return memo[KM][pos_of_last_station][station_remaining];
    }
    int ret = 2e9; // some large value
    if(station_remaining > 0) {

        // trying establishing a station on the current position
        int len = KM - pos_of_last_station;
        ret = min(ret, dp(KM + 1, KM, station_remaining - 1) + (2 * len * len + 3 * len) + cost[KM] );  // assuming cost[KM] is the cost to establish a station on KMth kilometer
    }
    ret = min(ret, dp(KM + 1, pos_of_last_station, station_remaining) );
    seen[KM][pos_of_last_station][station_remaining] = true; // sub problem visited
    memo[KM][pos_of_last_station][station_remaining] = ret;  // storing the result for future utilization

    return ret;

}

复杂性分析:需要O(MAX_KM * MAX_KM * MAX_STATION)时间和空间

警告:代码未经过测试