[BFS,A*,k短路径] 2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛 path (Problem - 6705)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6705

path

Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1250    Accepted Submission(s): 257


Problem Description
You have a directed weighted graph with  n vertexes and m edges. The value of a path is the sum of the weight of the edges you passed. Note that you can pass any edge any times and every time you pass it you will gain the weight.

Now there are q queries that you need to answer. Each of the queries is about the k-th minimum value of all the paths.
 
Input
The input consists of multiple test cases, starting with an integer  t (1t100), denoting the number of the test cases.
The first line of each test case contains three positive integers n,m,q. (1n,m,q5104)

Each of the next m lines contains three integers ui,vi,wi, indicating that the ith edge is from ui to vi and weighted wi.(1ui,vin,1wi109)

Each of the next q lines contains one integer k as mentioned above.(1k5104)

It's guaranteed that Σn ,ΣmΣq,Σmax(k)2.5105 and max(k) won't exceed the number of paths in the graph.
 
Output
For each query, print one integer indicates the answer in line.
 
Sample Input
1 2 2 2 1 2 1 2 1 2 3 4
 
Sample Output
3 3
Hint
1->2 value :1 2->1 value: 2 1-> 2-> 1 value: 3 2-> 1-> 2 value: 3
 
Source
 
Recommend
liuyiding

题意:

给n个点和m条条有权边.路径值为路径中的边权和,问第k小条的路径值为多少

思路:

考虑BFS,如果路径不止一条能知道路径值最小的路径,就能推出第2小的,由第2小推出第3小,由第k-1小推出第k小
先把边权排序,这样可以从边权最小的开始访问
搜索队列用优先队列可以每次取出路径和最小的,记录下答案,现在记录过当前点连接当前邻接点的答案了,就搜索当前点不连这个邻接点而是下一个邻接点的情况和当前邻接点连接下一个边权最小的当前邻接点的邻接点的情况
最后输出答案

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define pb(x) push_back(x)
 4 #define fi first
 5 #define se second
 6 typedef long long ll;
 7 typedef pair<ll,int> pii;
 8 const int amn=5e4+5;
 9 vector<pii> eg[amn];
10 struct node{
11     int u,v;
12     ll w;
13     node(int uu,int vv,ll ww){u=uu;v=vv;w=ww;}
14     bool operator<(const node a)const{return w>a.w;}
15 };
16 priority_queue<node> pq;
17 int n,m,q,u,v,k[amn],maxk;
18 ll w,ans[amn];
19 int main(){
20     int T;
21     scanf("%d",&T);
22     while(T--){
23         scanf("%d%d%d",&n,&m,&q);
24         for(int i=1;i<=n;i++)eg[i].clear();     ///初始化vector
25         while(pq.size())pq.pop();               ///初始化优先队列
26         for(int i=1;i<=m;i++){
27             scanf("%d%d%lld",&u,&v,&w);
28             eg[u].pb(pii(w,v));                 ///pair的first存边权是因为排序时先按first排再按second排
29         }
30         for(int i=1;i<=n;i++)sort(eg[i].begin(),eg[i].end());       ///对每个节点的邻接点按边权升序排序
31         maxk=0;
32         for(int i=1;i<=q;i++){
33             scanf("%d",&k[i]);          ///记录询问顺序,下面离线处理答案
34             maxk=max(maxk,k[i]);        ///记录一个最大的第k小,就要搜索到这里
35         }
36         for(int i=1;i<=n;i++)
37             if(eg[i].size())
38                 pq.push(node(i,0,eg[i][0].fi));     ///把每个点边权最小的邻接点加入搜索队列
39         int tp=0;
40         while(pq.size()){
41             node cu=pq.top();pq.pop();
42             ans[++tp]=cu.w;         ///记录路径和第tp小的答案
43             if(tp>=maxk)break;      ///知道了最大的第k小的路径就不用搜索了
44             if(cu.v+1<eg[cu.u].size())pq.push(node(cu.u,cu.v+1,cu.w-eg[cu.u][cu.v].fi+eg[cu.u][cu.v+1].fi));    ///现在记录过当前点连接当前邻接点的答案了,就搜索当前点不连这个邻接点而是下一个邻接点的情况
45             int v=eg[cu.u][cu.v].se;
46             if(eg[v].size())pq.push(node(v,0,cu.w+eg[v][0].fi));        ///当前邻接点连接下一个边权最小的当前邻接点的邻接点的情况
47         }
48         for(int i=1;i<=q;i++)printf("%lld\n",ans[k[i]]);        ///按询问顺序输出答案
49     }
50 }
51 /**
52 给n个点和m条条有权边.路径值为路径中的边权和,问第k小条的路径值为多少
53 考虑BFS,如果路径不止一条能知道路径值最小的路径,就能推出第2小的,由第2小推出第3小,由第k-1小推出第k小
54 先把边权排序,这样可以从边权最小的开始访问
55 搜索队列用优先队列可以每次取出路径和最小的,记录下答案,现在记录过当前点连接当前邻接点的答案了,就搜索当前点不连这个邻接点而是下一个邻接点的情况和当前邻接点连接下一个边权最小的当前邻接点的邻接点的情况
56 最后输出答案
57 **/

猜你喜欢

转载自www.cnblogs.com/Railgun000/p/11405204.html