1. 程式人生 > >(HDU 6024 女生專場)Building Shops 簡單DP詳細解答

(HDU 6024 女生專場)Building Shops 簡單DP詳細解答

Building Shops
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 701 Accepted Submission(s): 265

Problem Description
HDU’s n classrooms are on a line ,which can be considered as a number line. Each classroom has a coordinate. Now Little Q wants to build several candy shops in these n classrooms.

The total cost consists of two parts. Building a candy shop at classroom i would have some cost ci. For every classroom P without any candy shop, then the distance between P and the rightmost classroom with a candy shop on P’s left side would be included in the cost too. Obviously, if there is a classroom without any candy shop, there must be a candy shop on its left side.

Now Little Q wants to know how to build the candy shops with the minimal cost. Please write a program to help him.

Input
The input contains several test cases, no more than 10 test cases.
In each test case, the first line contains an integer n(1≤n≤3000), denoting the number of the classrooms.
In the following n lines, each line contains two integers xi,ci(−109≤xi,ci≤109), denoting the coordinate of the i-th classroom and the cost of building a candy shop in it.
There are no two classrooms having same coordinate.

Output
For each test case, print a single line containing an integer, denoting the minimal cost.

Sample Input
3
1 2
2 3
3 4
4
1 7
3 1
5 10
6 1

Sample Output
5
11

Source
2017中國大學生程式設計競賽 - 女生專場

題意:
有n個教室,現在想在這n個教室中建一些超市,問你最少費用為多少?
費用分為兩種:
1:在第i個教室建超市,費用因為ci
2:沒有建超市的教室的費用為它和它左邊最接近的超市的座標之間的距離

分析:
根據題目所給的時間,和題目的資料的大小,我們可以知道題目可以承受住時間複雜度為O(n^2)的演算法。

並且每個教室只有兩種方案,要麼建超市,要麼不建。這就很像是揹包問題了,所以我們就想到了dp.

我們設dp[i][0]表示在教室i不建超市時前i個教室的費用和的最小值;dp[i][1]表示在教室i建超市時前i個教室的費用和的最小值

那麼我們很快可以得出: dp[i][1] = min(dp[i-1][0],dp[i-1][1]) + ci

關於dp[i][0],由於可以承受住時間複雜度為O(n^2)的演算法,那麼我們就可以想到列舉離教室i最近的超市j的位置,然後取所有情況的最小值就可以了。

假設左邊最近超市為j,那麼教室j+1~教室i都不能建超市,所以教室j+1~教室i的費用分別為他們的位置到教室j之間的距離了。當前dp[i][0] = dp[j][1] +( 教室j+1~教室i的費用)

如果我們暴力求解,那麼時間複雜度會變成O(n^3),會超時。但是我們會發現由於j是從大到小變化的,所以就可以用:t += (i - j) * (nodes[j+1].x - nodes[j].x);來記錄教室j+1~教室i的費用和了。

關於 t += (i - j) * (nodes[j+1].x - nodes[j].x); 的解釋:
比如我們要算x3 - x1 , x2 - x1的sum,那麼由於保證了x是升序排列的,所以sum = (x3 - x2) + 2 * (x2 - x1).

AC程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int maxn = 3010;
const long long MM = 999999999999;
struct node
{
    long long x,c;
    bool operator < (node & a)
    {
        return this->x < a.x;
    }
    node():x(0),c(0){}
}nodes[maxn];

long long dp[maxn][2];

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%I64d%I64d",&nodes[i].x,&nodes[i].c);
        }
        sort(nodes,nodes+n);
        dp[0][1] = nodes[0].c;
        dp[0][0] = MM;
        for(int i=1;i<n;i++)
        {
            dp[i][1] = nodes[i].c + min(dp[i-1][0],dp[i-1][1]);
            dp[i][0] = MM;
            long long t = 0;
            for(int j=i-1;j>=0;j--)
            {
                t += (i - j) * (nodes[j+1].x - nodes[j].x);
                dp[i][0] = min(dp[i][0],dp[j][1] + t);
            }
        }
        printf("%I64d\n",min(dp[n-1][0],dp[n-1][1]));
    }
    return 0;
}