欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

cugoj-1697梦回三国

发布时间:2023/12/16 编程问答 40 豆豆
生活随笔 收集整理的这篇文章主要介绍了 cugoj-1697梦回三国 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

cugoj-1697

来源:2016华中师范大学“计蒜客杯”F题


题目大意:

给出n个点和m条边,再告诉你你个点中哪三个点是目标地点,然后要你求出连接这三个目标地点的最短路径。


解题思路:

这是最短路问题,先对三个目标地点求出其到所有其他点的最短路径,将结果保存后对所有的点进行一次遍历,计算该点到三个目标地点的距离之和,然后输出最小的结果。

为什么这么算能够确保结果是正确的呢?会不会有路径重叠的情况导致结果偏大?

*红色圈出部分即为重叠部分


我们可以具体讨论一下这中情况会不会发生:

当三个目标地点都能够互相连通时(不能连通则无解),必定能将两个目标地点先以最短路径连起来,这个时候我们再来考虑第三个目标地点,这时第三个点想要连入路径中只有两种方法,一是连在路径上,二是连在另外两个目标地点上。对于这两种情况都可以肯定的是路径中连入第三个目标地点的点到三个目标地点的路径都不会有重叠,而每种有重叠的情况都会有比其更好的不重叠的情况来代替。


解题要点:

由于n的大小为10^4,用二维数组储存图会超内存,所以这里采用邻接矩阵的储存方式。

dijkstra算法求最短路会导致超时,但经过观察后发现m的最大值为30000,是稀疏矩阵,所以用spfa算法求最短路。


附代码:

#include <iostream> #include <vector> #include <queue> #include <stdio.h> #include <string.h> using namespace std;struct road{int b,c; };int n; bool flag[10010]; int result[3][10010]; vector<road> map[10010];void Find(int start,int o){memset(flag,0,sizeof(flag));flag[start] = 1;int i,j,l,k,MIN,temp;for(i=1;i<=n;i++){result[o][i] = 999999999;}result[o][start] = 0;queue<int> q;q.push(start);while(q.empty() != true){temp = q.front();q.pop();for(i=0;i<map[temp].size();i++){j = map[temp].at(i).c;k = map[temp].at(i).b;if(result[o][k]>result[o][temp]+j){result[o][k] = result[o][temp]+j;q.push(k);}}} }int main(){road temp;int t,m,a,MIN,i,A,B,C;cin>>t;while(t--){scanf("%d%d",&n,&m);for(i=1;i<=n;i++) map[i].clear();for(i=0;i<m;i++){scanf("%d%d%d",&a,&temp.b,&temp.c);map[a].push_back(temp);B = temp.b;temp.b = a;map[B].push_back(temp);}scanf("%d%d%d",&A,&B,&C);Find(A,0);Find(B,1);Find(C,2);MIN = 999999999;for(i=1;i<=n;i++){if(result[0][i] == 999999999 || result[1][i] == 999999999 || result[2][i] == 999999999) continue;if(result[0][i]+result[1][i]+result[2][i]<MIN) MIN = result[0][i]+result[1][i]+result[2][i];}if(MIN == 999999999) cout<<"-1"<<endl;else cout<<MIN<<endl;}return 0; }


总结

以上是生活随笔为你收集整理的cugoj-1697梦回三国的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。