Write a program that finds a tree connecting all given points with the shortest total length of edges.
5 1 5 2 4 3 3 4 2 5 1 1 10000 0Sample 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;
}