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.
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 0
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;
}