PAT——甲级1046S:shortest Distance
Posted albert-yzp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PAT——甲级1046S:shortest Distance相关的知识,希望对你有一定的参考价值。
这道题,折磨了我一个多小时,前前后后写了三个算法。
1046 Shortest Distance (20 point(s))
The task is really simple: given N exits on a highway which forms a simple cycle, you are supposed to tell the shortest distance between any pair of exits.
Input Specification:
Each input file contains one test case. For each case, the first line contains an integer N (in [3,10?5??]), followed by N integer distances D?1??D?2?? ? D?N??, where D?i?? is the distance between the i-th and the (i+1)-st exits, and D?N?? is between the N-th and the 1st exits. All the numbers in a line are separated by a space. The second line gives a positive integer M (≤10?4??), with M lines follow, each contains a pair of exit numbers, provided that the exits are numbered from 1 to N. It is guaranteed that the total round trip distance is no more than 10?7??.
Output Specification:
For each test case, print your results in M lines, each contains the shortest distance between the corresponding given pair of exits.
Sample Input:
5 1 2 4 14 9 3 1 3 2 5 4 1
Sample Output:
3 10 7
题目特很简单,就是一个多个点组成的环形,求两个点之间的最短距离。阳历第一行5代表5个点,后面第i个数代表第一个点到第i+1个点的距离。等等。。。
然后我第一个想法是循环链表,第一次完成的写链表的代码,废了九牛二虎之力,写了一个循环链表,然后就贼舒服的求最短距离。
先贴出来的我写的代码
#include<cstdio> class Node { public: int num; int dis; Node* next; Node* pre; }; class cycleLinkList { public: cycleLinkList(); void insert_back(int num, int dis); int find_nearest(int prenum,int lastnum); //void displayAll(void); private: Node* head; }; cycleLinkList::cycleLinkList() { head = new Node; head->num = 0; head->pre = head; head->next = head;head->dis = 0; } void cycleLinkList::insert_back(int num, int dis) { Node* pre = head->next; while (pre->next!=head) { pre = pre->next; } Node* new_Node=new Node; new_Node->dis = dis; new_Node->num = num; new_Node->next = head; new_Node->pre = pre; pre->next->pre = new_Node; pre->next = new_Node; } int cycleLinkList::find_nearest(int prenum, int lastnum) { Node* pre = head->next; while (pre->num != prenum) { pre = pre->next; } int predistance=0,nextdistance=0; Node* pre_dir = pre; while (pre_dir->num != lastnum) { pre_dir = pre_dir->pre; predistance += pre_dir->dis; } Node* next_dir = pre; while (next_dir->num != lastnum) { nextdistance += next_dir->dis; next_dir = next_dir->next; } if (nextdistance >= predistance)return predistance; else return nextdistance; } /* void cycleLinkList::displayAll(void) { Node* _head = head->next; while (_head != head) { printf("%d %d ", _head->num, _head->dis); _head = _head->next; } printf("pre "); _head = head->pre; while (_head != head) { printf("%d %d ", _head->num, _head->dis); _head = _head->pre; } }*/ int main() { int n,m,dis; scanf("%d", &n); cycleLinkList data; for (int i = 0; i < n; i++){ scanf("%d", &dis); data.insert_back(i + 1, dis); } //data.displayAll(); //printf("insert"); scanf("%d", &m); for (int i = 0; i < m; i++){ int pre_num, last_num; scanf("%d%d", &pre_num,&last_num); printf("%d ",data.find_nearest(pre_num, last_num)); } return 0; }
写完之后运行很正常,当然是很舒服啦,但是。。。提交给OJ就是运行超时,我也很无奈,循环链表那么直观,竟然不让用。
那我就用数组呗,第二个想法,用数组。
1 #include<cstdio> 2 int main() 3 { 4 int dis[100005],n,m,total_dis=0; 5 memset(dis, 0, (100005*sizeof(int))); 6 scanf("%d", &n); 7 for (int i = 0; i < n; i++) 8 { 9 scanf("%d", &dis[i]); 10 total_dis += dis[i]; 11 } 12 scanf("%d", &m); 13 for (int i = 0; i < m; i++) { 14 int prenum, lastnum,nextdis=0; 15 scanf("%d%d", &prenum, &lastnum); 16 if (prenum > lastnum) { int temp = prenum;prenum = lastnum;lastnum = temp; } 17 18 for (int j = prenum - 1;j < lastnum - 1;j++) 19 nextdis += dis[j]; 20 if (total_dis - nextdis >= nextdis) printf("%d ", nextdis); 21 else printf("%d ", total_dis-nextdis); 22 } 23 return 0; 24 }
不过这个代码交上去,还是有一个运行超时。牛客PATOJ的全部通过,但PAT官网OJ最后一个超时。
主要原因出在我每次计算最短距离都要遍历数组,大概相当于O(m*n)的复杂度。运行时间太长。
然后我就求助教材了,发现可以给数组保存为第i个元素是第i个点到第i个点的距离,然后求两个点a,b之间的距离就可以直接dis[b]-dis[a]了。(其中a<b,否则交换)
这样的话就输入的时候遍历n次,找最短距离的时候遍历m次就行了。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int main() 5 { 6 int dis[100005], n, m, total_dis = 0; 7 scanf("%d", &n); 8 for (int i = 0; i < n; i++) 9 { 10 int temp; 11 scanf("%d", &temp); 12 dis[i] = total_dis; 13 total_dis += temp; 14 //printf("i: %d dis:%d total:%d ", i, dis[i],total_dis); 15 } 16 scanf("%d", &m); 17 for (int i = 0; i < m; i++) { 18 int prenum, lastnum; 19 scanf("%d%d", &prenum, &lastnum); 20 if (prenum > lastnum) swap(prenum, lastnum); 21 int temp = dis[lastnum-1] - dis[prenum-1]; 22 printf("%d ",min(temp,total_dis-temp)); 23 } 24 return 0; 25 }
然后终于通过啦。
这也学到了一点,拿到题先想想有没有简化的方法,按照最简单的思维去写代码,往往可能运行超时。
就像这道题最后一种方法,就简化了很多。越简单的题越需要脑子,不要一拿上来就做。
int main(){int dis[100005],n,m,total_dis=0;memset(dis, 0, (100005*sizeof(int)));scanf("%d", &n);for (int i = 0; i < n; i++){scanf("%d", &dis[i]);total_dis += dis[i];}scanf("%d", &m);for (int i = 0; i < m; i++) {int prenum, lastnum,nextdis=0;scanf("%d%d", &prenum, &lastnum);if (prenum > lastnum) { int temp = prenum;prenum = lastnum;lastnum = temp; }for (int j = prenum - 1;j < lastnum - 1;j++)nextdis += dis[j];if (total_dis - nextdis >= nextdis) printf("%d ", nextdis);else printf("%d ", total_dis-nextdis);}return 0;}
以上是关于PAT——甲级1046S:shortest Distance的主要内容,如果未能解决你的问题,请参考以下文章