ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

VJ - H - Almost the shortest route - 图论(反向建图)

2020-01-15 09:03:57  阅读:384  来源: 互联网

标签:arr Almost max VJ vertex int 建图 id dis


https://vjudge.net/contest/351913#problem/H

N cities (2 ≤ N ≤ 10 000 ) are connected by a network of M one-way roads (1 ≤ M < 100 000 000 ). It is known that these roads do not cross outside the cities. The numeration of the cities and the roads starts from 1.There is at most one road from any city to another one. The length of each road does not exceed 10 000 .

The company for which you work sends you on a business trip from city 1 to city N on your personal car. The trip expenses will be compensated to you only if the distance you drive will differ from the shortest possible by no more than K (0 ≤ K ≤ 10 000 ).

The task is to determine on which roads you can drive to have the right to the compensation. That means the list of all roads that appear on at least one route from city 1 to city N where the length of the route does not exceed the length of the shortest route by more than K.

 

Input

The input consists of M+1 lines. The first line contains the numbers NM, and K. Each next line describes one road and contains the initial city number, the final city number and the length of the road. All numbers are integers and separated from each other by one or more spaces.

Output

The output consists of several lines. The first line contains the integer L – the number of roads you can use. The following L lines contain the numbers of the roads in ascending order.

Sample Input

4 5 1
1 2 1
1 3 4
2 3 1
2 4 3
3 4 1

Sample Output

4
1
3
4
5


这一题一开始我的思路是先在起点跑一次dijkstra,然后得到起点到达终点的最短路,依据这个最短路进行剪枝dfs搜到所有的边。
上代码(虽然爆栈了,不过还是发上来,提醒一下自己不这么写)

 1 #include <iostream>
 2 #include <set>
 3 #include <vector>
 4 #define Maxsize 10000 + 1
 5 #define INF 0x3fffffff
 6 using namespace std;
 7 struct node{
 8     int to;
 9     int dis;
10     int id;
11 };
12 int vertex,edge,max_extra;
13 int max_dis;
14 set<int> cnt;
15 vector<node> arr[Maxsize];
16 int d[Maxsize];
17 bool vis[Maxsize];
18 int help = INF;
19 bool dfs(int id,int sum){  // dfs返回一个布尔值,当最终搜到终点,说明之前的所有边都可以使用
20     if(sum > max_dis)return false; // 剪枝
21     else if(id == vertex){
22         if(sum <= help){
23             help = sum;
24             for(vector<node> :: iterator it = arr[id].begin(); it != arr[id].end(); it++){  // 有可能到达终点后继续跑,那样的边也是合理的
25                 if(dfs(it->to,sum + it->dis))
26                 cnt.insert(it->id);
27             }
28         }
29         return true;
30     }else{
31         int flag = 0;
32         for(vector<node> :: iterator it = arr[id].begin(); it != arr[id].end(); it++){
33             if(dfs(it->to,sum + it->dis)){
34                 flag = 1;
35                 cnt.insert(it->id);
36             }
37         }
38         if(flag)return true;
39         else return false;
40     }
41 }
42 int main(){
43     ios :: sync_with_stdio(false);
44     cin.tie(0);
45     cout.tie(0);
46     
47     cin >> vertex >> edge >> max_extra;
48     int from;
49     for(int i = 1; i <= edge; i++){
50         node a;
51         cin >> from >> a.to >> a.dis;
52         a.id = i;
53         arr[from].push_back(a);
54     }
55     
56     fill(d,d+Maxsize,INF);
57     fill(vis,vis+Maxsize,false);
58     d[1] = 0;
59     
60     for(int i = 0; i < vertex; i++){
61         int find_min = INF;
62         int find_v = -1;
63         for(int i = 1; i <= vertex; i++){
64             if(vis[i] == false && d[i] < find_min){
65                 find_min = d[i];
66                 find_v = i;
67             }
68         }
69         if(find_v == vertex)break;
70         vis[find_v] = true;
71         for(vector<node> :: iterator it = arr[find_v].begin(); it != arr[find_v].end(); it++){
72             if(d[it->to] > find_min + it->dis){
73                 d[it->to] = find_min + it->dis;
74             }
75         }
76     }
77     max_dis = d[vertex] + max_extra;
78     dfs(1,0);
79     cout<<cnt.size()<<endl;
80     for(set<int> :: iterator it = cnt.begin(); it != cnt.end(); it++){
81         cout<<*it<<endl;
82     }
83     return 0;
84 }

 

为什么会爆呢?其实数据量并没有题目写的那么大(顶多1e5),更多可能是因为每一条边都很短,导致递归过深了。

 

接下来是正解: 两边dijkstra,第一遍从起点跑,得出每一个顶点距离起点的最短距离。第二遍从终点跑,反向建图,得到每一个点到终点的最短距离。

这样一来,我们就可以知道任意一条边的两个端点分别距离起点和终点的最短距离了。

那么如何判断一个边是否可用呢? 只需要 写 d [ start - >left_vertex ]  +  edge_length + d[ right_vertex  -> end ]   <= d[ start -> end ]  + max_extra

一会上代码~

标签:arr,Almost,max,VJ,vertex,int,建图,id,dis
来源: https://www.cnblogs.com/popodynasty/p/12194914.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有