HDU - 3516 Tree Construction(區間dp)

傳送門

Consider a two-dimensional space with a set of points (xi, yi) that satisfy xi < xj and yi > yj for all i < j. We want to have them all connected by a directed tree whose edges go toward either right (x positive) or upward (y positive). The figure below shows an example tree. 


Write a program that finds a tree connecting all given points with the shortest total length of edges.
InputThe input begins with a line that contains an integer n (1 <= n <= 1000), the number of points. Then n lines follow. The i-th line contains two integers xi and yi (0 <= xi, yi <= 10000), which give the coordinates of the i-th point. OutputPrint the total length of edges in a line. Sample Input
5
1 5
2 4
3 3
4 2
5 1
1
10000 0
Sample Output
12
0
題意:給出平面上n個點,要求把這些點連起來構成一棵樹連起來的路徑最短,樹只能向左和向右生長。感覺這是類似石子合併的一個區間dp,但是數據量有點大,所以要用到平行四邊形優化(第一次寫平行四邊形優化的題目,竟然一次過,開心)。我感覺平行四邊形優化,主要是證明出滿足四邊形不等式,然後會用就行了,平行四邊形不等式爲:w(i, j) + w(i1, j1) <= w(i1 , j) w(i ,j1),只要能證明出這個不等式就可以使用平行四邊形優化。

確定了這一點。就是找動態轉移方程了,dp[i][j]表示合併i到j所有的點之後樹的最小長度

dp[i][j] = dp[i][k] + dp[k+1][j] + abs(no[k+1].x - no[i].x + no[k].y - no[j].y);


#include<iostream>
#include<stdio.h>
#include<string>
#include<math.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
#include<iterator>
using namespace std;
typedef unsigned long long ll;
const int inf = 0x3f3f3f3f ;
struct node{
    int x , y ;
}no[1005];
int n ;
int dp[1005][1005];
int s[1005][1005];
int main(){
    while(~scanf("%d" , &n)){
        for(int i = 1 ; i <= n ; i ++){
            scanf("%d %d" , &no[i].x , &no[i].y);
        }
        for(int i = 0 ; i <= n ; i ++){
            for(int j = 0 ; j <= n ; j ++){
                dp[i][j] = inf;
            }
        }
        for(int i = 0 ; i <= n ; i ++){
            s[i][i] = i ;
            dp[i][i] = 0;
        }

        for(int len = 1 ; len < n ; len ++){
            for(int i = 1 ; i <= n - len ; i ++){
                int j = i + len;
                //dp[i][j] = inf;
                for(int k =  s[i][j - 1] ; k <= s[i + 1][j] ; k ++){
                    if(dp[i][j] > dp[i][k] + dp[k+1][j] + abs(no[k+1].x - no[i].x + no[k].y - no[j].y)){
                        dp[i][j] = dp[i][k] + dp[k+1][j] + abs(no[k+1].x - no[i].x + no[k].y - no[j].y);
                        s[i][j] = k ;
                    }

                }
            }
        }
        cout<<dp[1][n]<<endl;
    }
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章