3 1 1 10 3 1 20 3 30 5 10 2 1 10 2 11
830 4090 1642
J.L. Bentley 建议通过只考虑双调旅程(bitonic tour)来简化问题,这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点。下图(b)显示了同样的7个点的最短双调路线。在这种情况下,多项式的算法是可能的。事实上,存在确定的最优双调路线的O(n*n)时间的算法。
注:在一个单位栅格上显示的平面上的七个点。 a)最短闭合路线,长度大约是24.89。这个路线不是双调的。b)相同点的集合上的最短双调闭合路线。长度大约是25.58。
这是一个算导上的思考题15-1。
首先将给出的点排序,关键字x,重新编号,从左至右1,2,3,…,n。
定义p[i][j],表示结点i到结点j之间的距离。
定义d[i][j],表示从i连到1,再从1连到j,(注意,i>j,且并没有相连。)
对于任意一个点i来说,有两种连接方法,一种是如图(a)所示,i与i-1相连,另一种呢是如图(b),i与i-1不相连。
根据双调旅程,我们知道结点n一定与n相连,那么,如果我们求的d[n][n-1],只需将其加上p[n-1][n]就是最短双调闭合路线。
根据上图,很容易写出方程式:
dp[i][j]=dp[i-1][j]+dist[i][i-1];
dp[i][i-1]=min(dp[i][i-1],dp[i-1][j]+dist[j][i]);
/************************************************************************* > File Name: hdu-4824-Disk_Schedule.cpp > Author: nealgavin > Mail: nealgavin@126.com > Created Time: Sun 25 May 2014 07:38:59 PM CST ************************************************************************/ #include<iostream> #include <cstdio> #include <cstring> using namespace std; const int mm = 1000+9; const int oo = 1e9; int dp[mm][mm],d[mm]; int n; int dis(int x,int y) { if(d[x] < d[y]) x^=y^=x^=y; int distance = d[x]-d[y]; return min(distance,360-distance); } void init() { dp[1][0] = dis(0,1); } int DP() { for(int i=2;i<=n;++i) { dp[i][i-1] = oo; for(int j=0;j<i-1;++j) { dp[i][i-1] = min(dp[i][i-1],dp[i-1][j]+dis(i,j)); dp[i][j] = dp[i-1][j] + dis(i,i-1); } } int ans = oo; for(int i=0;i<n;++i) ans = min(ans,dp[n][i]+dis(i,n)); return ans; } int main() { int cas; while(~scanf("%d",&cas)) { while(cas--) { scanf("%d",&n); int x; d[0] = 0; for(int i=1;i<=n;++i) scanf("%d %d",&x,&d[i]); init(); printf("%d\n",DP()+x*800+n*10); } } return 0; }