Disk Schedule
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2368 Accepted Submission(s): 333
对于每组测试数据,第一行包含一个整数N(0<N<=1000),表示要读取的数据的数量。之后每行包含两个整数T和S(0<T<=1000,0<= S<360),表示每个数据的磁道和扇区,磁道是按升序排列,并且没有重复。
J.L. Bentley 建议通过只考虑双调旅程(bitonic tour)来简化问题,这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点。下图(b)显示了同样的7个点的最短双调路线。在这种情况下,多项式的算法是可能的。事实上,存在确定的最优双调路线的O(n*n)时间的算法。
注:在一个单位栅格上显示的平面上的七个点。 a)最短闭合路线,长度大约是24.89。这个路线不是双调的。b)相同点的集合上的最短双调闭合路线。长度大约是25.58。
这是一个算导上的思考题15-1。
首先将给出的点排序,关键字x,重新编号,从左至右1,2,3,…,n。
定义d[i][j],表示结点i到结点j之间的距离。
定义dp[i][j],表示从i连到1,再从1连到j,(注意,i>j,且并没有相连。)
对于任意一个点i来说,有两种连接方法,一种是如图(a)所示,i与i-1相连,另一种呢是如图(b),i与i-1不相连。
根据双调旅程,我们知道结点n一定与n相连,那么,如果我们求的dp[n][n-1],只需将其加上d[n-1][n]就是最短双调闭合路线。
根据上图,很容易写出方程式:
dp[i][j]=dp[i-1][j]+d[i][i-1];
dp[i][i-1]=min(dp[i][i-1],dp[i-1][j]+d[j][i]);
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- using namespace std;
- const int maxn = 1010;
- int dp[maxn][maxn];
- int d[maxn][maxn];
- struct point
- {
- int x, y;
- }a[maxn];
- int dis(int i, int j) //计算两点之间的距离
- {
- int p,q;
- if(a[i].y>a[j].y)
- q=(360+a[j].y-a[i].y)%360;
- else
- q=(360+a[i].y-a[j].y)%360;
- p=abs(a[i].y-a[j].y)>q?q:abs(a[i].y-a[j].y); //求出小弧的长度
- return (abs(a[i].x-a[j].x)*400+p); //距离=两点的轨道差*400+两点的扇区差
- }
- int main()
- {
- int t,n;
- scanf("%d",&t);
- while(t-- )
- {
- scanf("%d", &n);
- a[1].x=0;
- a[1].y=0; //把起点(0,0)加上
- for(int i = 2; i <= n+1; i++)
- scanf("%d %d", &a[i].x, &a[i].y);
- for(int i = 1; i <= n+1; i++)
- {
- for(int j = 1; j <= n+1; j++)
- {
- d[i][j] = dis(i, j); //d[i][j]为i点到j点的距离
- }
- }
- dp[1][2] = d[1][2];
- for(int i = 3; i <= n+1; i++)
- {
- for(int j = 1; j < i-1; j++)
- {
- dp[j][i] = dp[j][i-1] + d[i-1][i]; /* dp[j][i]为j点到1点,再从1点到i点的距离,这一步是为下一循环求dp[i][i+1]做准备,其实就是图a */
- }
- dp[i-1][i] = 999999999;
- for(int j = 1; j < i-1; j++)
- {
- int sum = dp[j][i-1] + d[j][i];
- if(dp[i-1][i] > sum)
- dp[i-1][i] = sum; /* dp[i-1][i]为i-1点到1点,再从1点到i点的最短距离,这个距离只要加上边d[i-1][i]就是从1点到i点的最短闭合旅程,其实就是图b */
- }
- }
- dp[n+1][n+1] = dp[n][n+1] + d[n][n+1];
- printf("%d\n", dp[n+1][n+1]+10*n); /* dp[n+1][n+1]就是最终的最短闭合旅程,n+1点到1点,再从1点到n+1点的最短距离 ,10*n为读取点中数据的时间 */
- }
- return 0;
- }