hdu 3516 Tree Construction

來源:互聯網
上載者:User
Tree Construction

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 684    Accepted Submission(s): 364

Problem DescriptionConsider 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

51 52 43 34 25 1110000 0
 

Sample Output

120
 

Source2010 ACM-ICPC Multi-University Training
Contest(8)——Host by ECNU  

Recommendzhouzeyong 【題目意思】給你很多個點,這些點滿足a set of points (xi, yi) that satisfy xi < xj and yi > yj for all i < j.讓你用一棵樹把所有點連在一齊,樹只能往上跟右生長,求樹的總長度最小
【解題思路】類似石子合并,加上四邊形最佳化就行了
定義狀態 dp[i,j]表示點i到點j合并在一起的最小花費(樹枝的長度),
狀態轉移方程:dp[i,j]= min(dp[i,k]+dp[k+1,j]+cost(i,j) ) i<k<j
cost(i,j)=py[k]-py[j]+px[k+1]-px[i];
當j固定時,cost(i,j)單調遞減函數
我們猜測cost(i,j)滿足四邊形不等式
證明: 
F(i)=cost(i,j+1)-cost(i,j)=py[j]-py[j+1]是一個與i無關的多項式,
所以j固定時,F(i)滿足四邊形不等式,得證。
s[i,j]=k;s[i-1,j] <= s[i,j] <= s[i,j+1];
由於決策s具有單調性,因此狀態轉移方程可修改為:
dp[i,j]= min(dp[i,k]+dp[k+1,j]+cost(i,j) ) s[i-1,j] <=k<= s[i,j+1];
開始輕鬆的寫出了動態方程:
dp[i][j]=MIN(dp[i][k]+dp[k+1][j]+x[k+1]-x[i]+y[k]-y[j]  i<=k<=j
於是寫了一個樸素枚舉的程式。果斷逾時了。百思不得其解。搜了下題解才知道要
用四邊形不等式最佳化。即縮小枚舉範圍時間發雜度降到o(n^2)。四邊形不等式一片
空白。這是我第一個四邊形不等式最佳化dp。看了各種資料後終於明白大部分思想了
就是四邊形條件不好證明。不過簡單運用會點了。dp依然很菜。繼續加油!

#include <iostream>#include<stdio.h>#include<string.h>#define MAX(a,b) ((a)>(b)?(a):(b))#define MIN(a,b) ((a)<(b)?(a):(b))#define positive(a) ((a)>0?(a):-(a))using namespace std;int x[1010],y[1010];//記錄x,y座標int n,ans,dp[1010][1010],s[1010][1010];void solve(){    int i,j,k,len,l,r,temp;    memset(dp,0x3f,sizeof dp);    for(i=1;i<=n;i++)    {        dp[i][i]=0;//把自己串連起來肯定需要0        s[i][i]=i;//初始為k的枚舉範圍為i到i。    }    for(len=2;len<=n;len++)//枚舉區間長度。由動態方程    {                      //dp[i][j]=MIN(dp[i][k]+dp[k+1][j]+x[k+1]-x[i]+y[k]-y[j]                           //可知dp[i][k],dp[k+1][j]均是比dp[i][j]小的區間為了計算dp[i][j]必須算出比                           //其小的區間dp。所以從小到大枚舉區間長度        for(i=n-len+1;i>0;i--)//i必須從大到小枚舉。因為計算dp[i][j]時要用到dp[i][k],dp[k+1][j]                             //k+1>i所以為了保證k+1已經算出必須倒著枚舉        {            j=i+len-1;            l=s[i][j-1];//由四邊形不等式s[i][j-1]<=k<=s[i+1][j]            r=MIN(j-1,s[i+1][j]);//計算s[i][j]需要s[i][j-1]和s[i+1][j]                                 //s[i+1][j]前面已算出.s[i][j-1]範圍比s[i][j]小也已算出            for(k=l;k<=r;k++)//枚舉l,r,之間的k即可            {                temp=dp[i][k]+dp[k+1][j]+x[k+1]-x[i]+y[k]-y[j];                if(temp<dp[i][j])                {                    dp[i][j]=temp;                    s[i][j]=k;//得出i和j之間枚舉k的範圍為i到k                }            }        }    }    ans=dp[1][n];}int main(){    int i;    while(~scanf("%d",&n))    {        for(i=1;i<=n;i++)            scanf("%d%d",x+i,y+i);        solve();        printf("%d\n",ans);    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.