ACM解题总结——HihoCoder1138

来源:互联网 发布:2016网络作家排名 编辑:程序博客网 时间:2024/04/30 15:16
题目来源:
   HihoCoder 1138
题目要求:
   给定N个小岛的坐标序列:(x1, y2), (x2, y2)...(xN, yN),从(x1, y1)到(xN,yN)之间的最短距离。齐总:两个小岛(xi,yi)和(xj,yj)之间的距离由下面的式子定义:
    d(i,j) = min{|xi - xj|, |yi-yj|}
即:两个小岛的距离是他们横坐标和纵坐标差值的较小者。 


解答:
    这个题目思路还是比较简单的,主要采用dijkstra算法求最短路径。但是,依照题目的描述,任意两个小岛都是可达的, 即图中每个点都有N-1条边和其他的点相连。dijkstra算法的时间复杂度是O(n²)。这样的时间复杂度在运行本题的测试数据时会超时。因此需要对算法进行一定的优化,优化方法如下:

·图优化:

    通过对图中的N个点进行排序,可以得到每个点在x方向和y方向上的距离最近的点,如下图:


通过寻找x前驱、x后继、y前驱、y后继,可以为每一个点找到4个距离最近的点。而对于起点s,它到终点e的最短路径一定会至少包含s的4个最近点中的1个。这个结论可以用反证法证明,如下:
    假设存在一条从s到e的最短路径L = (s, m1, m2, ..., mk, e)不包含任意一个s的最邻近点,则考虑边子路径(s, m1)的长度:
    d(s, m1) = min{|s_x - m1_x|, |s_y, m1_y|}
    由于m1不是s的最邻近点,所以点s到点m1之间一定存在一个s的最邻近点m0,
    以下分两种情况考虑:
    (1) 如果d(s, m1) = |d_x - m1_x|,那么点m0一定是s在横轴x方向上的最邻近点,并且m0_x一定介于s_x和m1_x之间,因此:
        |s_x - m1_x| = |s_x - m0_x| + |m0_x - m1_x| 

如下图所示:

    

将点m0插入到点s和点m1之间后,就可以得到一条新的路径:L' = (s, m0, m1, m2, ..., mk, e),此时,将两条路径的长度做差:
    d(L) - d(L') = d(s, m1) - d(s, m0) - d(m0, m1) = 
|s_x - m1_x| - [d(s, m0) + d(m0, m1)]
而根据题目中对于两个点的距离的定理,我们可以得到这样的结论:任意两点间的距离:
    d(i, j) ≤ |i_x - j_x| 并且 d(i, j) ≤ |i_y - j_y|
于是,就可以得到:
    d(L) - d(L') = 
|s_x - m1_x| - [d(s, m0) + d(m0, m1)] ≥ 
                   
|s_x - m1_x| - [s_x - m0_x| + |m0_x - m1_x|] = 0
因此:d(L) ≥ d(L'),于是就找到了一条总长度小于L的路径L',路径L不是最短路径,这和假设是矛盾的。
    (2) 
如果d(s, m1) = |d_y - m1_y|,那么点m0一定是s在纵轴y方向上的最邻近点,并且m0_y一定介于s_y和m1_y之间。之后的分析则和情况(1)基本相同。
    
    以此类推,m0到e的最短路径也一定会包含m0的邻近点m1,m1到e的最短路径也一定会经过m1的邻近点......因此,在计算最短路径时,只要考虑每个点的最邻近的4个点即可,即每个点都最多只有4条和其他点相连的边,这样图中的边就会大大减少。

·计算优化:
    最朴素的dijkstra算法在每一轮迭代需要在未扫描的点中选择距离最近的点,时间复杂度是O(n),然后遍历该点所连接的边,更新和这个点邻接的点的距离。迭代的次数为点的个数n。因此遍历点的过程在整个算法中的执行时间是O(n²)。而算法结束时,图中的每条边均会被访问一次,因此遍历边,更新邻接点的距离的过程的执行时间是O(E)。因此传统的dijkstra算法的时间复杂度是O(n² + E)由于非多重图中边的数目E一定小于n(n-1)/2,因此:E ≤ 
n(n-1)/2 = O(n²),所以整个算法的时间复杂度是O(n²)。
    算法的优化关注的是每次迭代寻找距离最短的点的过程,通过建立最小二叉堆就可以实现这个优化,保证每轮迭代时堆顶的元素一定是距离最小的点,将该点出堆操作后,对堆进行调整,这个过程时间复杂度是O(lgn),于是算法的时间复杂度就优化为 O(nlgn + E),此时,由于我们的图中每个点最多4条边,因此这里的边数E ≤ 4n = O(n),因此整个算法的时间复杂度是O(nlgn),这样就不会超时了。

 

输入输出格式:
    输入:输入的第一行为一个数字N,表示有N个小岛;接下来的N行为每个小岛的坐标(xi, yi)。
    输出:输出一个数字,表示输入中的第一个小岛到最后一个小岛的最短距离。

数据范围:
    N ≤ 100,000
    0 ≤ xi ≤ 1,000,000,000 

    0 ≤ yi ≤ 1,000,000,000


程序代码:

/****************************************************//* File        : HihoCoder1138.cpp                  *//* Author      : Zhang Yufei                        *//* Date        : 2016-04-11                         *//* Description : HihoCoder ACM program. (submit:g++)*//****************************************************/#include<stdio.h>#include<stdlib.h>/* * Define the structure to store the graph. * Parameters: *@index: The index of this node in heap.  *@distance: The distance between the start node and this node. *@x & @y: The coordinates of this node. *@p1 & @p2 & @p3 & @p4: The 4 nodes which are nearest to this node. */typedef struct node {int index;int x, y;int distance;struct node *p1, *p2, *p3, *p4;} island;// Define the adjacency list of the graph.island **islands;// Record the start and the end node.island *start, *end;// Record the heap size.int heap_size;/* * These 2 functions are used for comparing in quick sort process. * Parameters: *@p1 & @p2: The 2 objects to compare. * Returns: *If p1 > p2, returns 1; if p1 = p2, returns 0,  *if p1 < p2 returns -1; */int cmp1(const void *p1, const void *p2);int cmp2(const void *p1, const void *p2);/* * This function is an iterating function in the process of heap sorting. * Parameters: *@index: The current element to operate. * Returns: *None. */void min_heapify(int index);/* * This function delete the top elements from the heap. * Parameters: *None. * Returns: *The elements deleted from heap. */island* delete_heap(void);/* * This function upeate the heap. Call this function when update  * the distance of a node. * Parameters: *@index: The index of the updated node. * Returns: *None. */void update_heap(int index);/* * This function computes the distance between 2 nodes. * Parameters: *@i1 & i2: The 2 nodes to compute. * Returns: *The distance between these 2 nodes. */int compute_distance(island* i1, island* i2); /* * The main program. */int main(void) {// Deal with input:int N;scanf("%d", &N);islands = (island**) malloc(sizeof(island*) * N); for(int i = 0; i < N; i++) {islands[i] = (island*) malloc(sizeof(island));scanf("%d %d", &islands[i]->x, &islands[i]->y);islands[i]->distance = 1000000001;islands[i]->p1 = islands[i]->p2 = islands[i]->p3 = islands[i]->p4 = NULL;}start = islands[0];end = islands[N - 1];start->distance = 0;// Upeate the adjacency information: qsort(islands, N, sizeof(island*), cmp1);islands[0]->p1 = NULL;islands[0]->p2 = islands[1]; for(int i = 1; i < N - 1; i++) {islands[i]->p1 = islands[i - 1];islands[i]->p2 = islands[i + 1];}islands[N - 1]->p1 = islands[N - 2];islands[N - 1]->p2 = NULL;qsort(islands, N, sizeof(island*), cmp2);islands[0]->p3 = NULL;islands[0]->p4 = islands[1]; for(int i = 1; i < N - 1; i++) {islands[i]->p3 = islands[i - 1];islands[i]->p4 = islands[i + 1];}islands[N - 1]->p3 = islands[N - 2];islands[N - 1]->p4 = NULL;// Create heap:for(int i = 0; i < N; i++) {islands[i]->index = i;} islands[start->index] = islands[0];islands[start->index]->index = start->index;islands[0] = start;islands[0]->index = 0;heap_size = N;// Compute the shortest path in dijkstra algorithm:for(int i = 0; i < N; i++) {island* cur = delete_heap();int d;if(cur->p1 != NULL && cur->p1->index < heap_size) {d = compute_distance(cur, cur->p1);d += cur->distance;if(d < cur->p1->distance){cur->p1->distance = d;update_heap(cur->p1->index);}}if(cur->p2 != NULL && cur->p2->index < heap_size) {d = compute_distance(cur, cur->p2);d += cur->distance;if(d < cur->p2->distance){cur->p2->distance = d;update_heap(cur->p2->index);}}if(cur->p3 != NULL && cur->p3->index < heap_size) {d = compute_distance(cur, cur->p3);d += cur->distance;if(d < cur->p3->distance){cur->p3->distance = d;update_heap(cur->p3->index);}}if(cur->p4 != NULL && cur->p4->index < heap_size) {d = compute_distance(cur, cur->p4);d += cur->distance;if(d < cur->p4->distance){cur->p4->distance = d;update_heap(cur->p4->index);}}}printf("%d\n", end->distance); return 0;} /* * These 2 functions are used for comparing in quick sort process. * Parameters: *@p1 & @p2: The 2 objects to compare. * Returns: *If p1 > p2, returns 1; if p1 = p2, returns 0,  *if p1 < p2 returns -1; */int cmp1(const void *p1, const void *p2) {island *i1 = *((island**) p1);island *i2 = *((island**) p2);if(i1->x > i2->x) {return 1;} else if(i1->x < i2->x) {return -1;} else {if(i1->y > i2->y) {return 1;} else if(i1->y == i2->y) {return 0;} else {return -1;}}}int cmp2(const void *p1, const void *p2) {island *i1 = *((island**) p1);island *i2 = *((island**) p2);if(i1->y > i2->y) {return 1;} else if(i1->y < i2->y) {return -1;} else {if(i1->x > i2->x) {return 1;} else if(i1->x == i2->x) {return 0;} else {return -1;}}}/* * This function is an iterating function in the process of heap sorting. * Parameters: *@index: The current element to operate. * Returns: *None. */void min_heapify(int index) {int min = islands[index]->distance;int min_index = index;if(2 * index + 1 < heap_size) {if(islands[index * 2 + 1]->distance < min) {min = islands[index * 2 + 1]->distance;min_index = 2 * index + 1;}}if(2 * index + 2 < heap_size) {if(islands[index * 2 + 2]->distance < min) {min = islands[index * 2 + 2]->distance;min_index = 2 * index + 2;}}if(min_index != index) {island* swap = islands[index];islands[index] = islands[min_index];islands[min_index] = swap;islands[index]->index = index;islands[min_index]->index = min_index;min_heapify(min_index);}}/* * This function delete the top elements from the heap. * Parameters: *None. * Returns: *The elements deleted from heap. */island* delete_heap(void) {heap_size--;island* swap = islands[0];islands[0] = islands[heap_size];islands[heap_size] = swap;islands[0]->index = 0;islands[heap_size]->index = heap_size;min_heapify(0);return swap;}/* * This function upeate the heap. Call this function when update  * the distance of a node. * Parameters: *@index: The index of the updated node. * Returns: *None. */void update_heap(int index) {while(index > 0) {if(islands[(index - 1) / 2]->distance > islands[index]->distance) {island* swap = islands[index];islands[index] = islands[(index - 1) / 2];islands[(index - 1) / 2] = swap;islands[index]->index  = index;islands[(index - 1) / 2]->index = (index - 1) / 2;index = (index - 1) / 2;} else {break;}}}/* * This function computes the distance between 2 nodes. * Parameters: *@i1 & i2: The 2 nodes to compute. * Returns: *The distance between these 2 nodes. */int compute_distance(island* i1, island* i2) {int delta_x = abs(i1->x - i2->x);int delta_y = abs(i1->y - i2->y);return delta_x < delta_y ? delta_x : delta_y; }


0 0
原创粉丝点击