POJ 2679:Adventurous Driving(SPFA+DFS)

http://poj.org/problem?id=2679

Adventurous Driving

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 1596   Accepted: 455

Description

After a period of intensive development of the transportation infrastructure, the government of Ruritania decides to take firm steps to strengthen citizens‘ confidence in the national road network and sets up a compensation scheme for adventurous driving (CSAD). Those driving on a road with holes, bumps and other entertaining obstacles get compensation; those driving on a decent road pay tax. These compensations and taxes are obtained and paid in cash on entry on each road and depend on the entry point on the road. What you get and pay driving on a road from A to B may be different from what you get and pay driving on the same road from B to A. The Ruritarian authorities call fee the amount of money paid as tax or obtained as compensation on entry on a road. A positive fee is a tax; a negative fee stands for compensation. 
John Doe plans to take advantage of CSAD for saving money he needs to repair his old car. When driving from A to B, John follows a path he calls optimal: a path that is rewarding and has the minimal length out of the paths with the minimal weight from A to B. In John‘s opinion, a path is rewarding if all the roads in the path are rewarding, and a road (X,Y) is rewarding if it has the minimal entry fee out of the roads leaving X. The weight of a path is the sum of the entry fees paid along the path. The length of a path cumulates the length of the roads in the path. The problem is helping John to compute the weight and the length of an optimal path from A to B on a given map. 
For example, on the illustrated road map vertices designate cities and edges stand for roads. The label fuv[L]fvu of the road (u,v) shows the fee fuv for driving from u to v, the fee fvu for driving from v to u, and the length L of the road. The path (0,2,4,3,5) from 0 to 5 is optimal: it is rewarding, has weight 2 (-1+3+0+0) and length 50 (5+10+5+30). The path (0,1,4,3,5), although rewarding and of weight 2, has length 51. The path (0,3,5) has weight 0 and length 20 but it is not rewarding.

Input

Write a program that reads several data sets from a text file. Each data set encodes a road map and starts with four integers: the number 1<=n<=1100 of towns on the map, the number 0<=m<=5000 of roads, the departure town 0<=A<=n-1, and the destination town 0<=B<=n-1. Follow m data quintuples (u,v,fuv[L]fvu), where u and v are town identifiers (integers in the range 0..n-1), 100<=fuv, fvu<=100 are integer fees for driving on the road (u,v), and 1<=L<=100 is the integer length of the road. The quintuples may occur in any order. Except the quintuples, which do not contain white spaces, white spaces may occur freely in input. Input data terminate with an end of file and are correct.

Output

For each data set, the program prints – from the beginning of a line – the weight and the length of an optimal path, according to John‘s oppinion, from A to B. If there is no optimal path from A to B the text VOID is printed. If the weight of the optimal path from A to B has no lower bound the text UNBOUND is printed.

Sample Input

3 3 0 2 (0,1,0[1]0) (0,2,1[1]0) (1,2,1[1]0)
3 3 0 2 (0,1,-1[1]1) (0,2,0[1]0) (1,2,0[1]1)
7 11 0 5 (0,1,-1[6]4) (0,2,-1[5]4) (0,3,0[1]0)  (1,4,3[10]1)
(2,4,3[10]1) (3,4,0[5]0)  (3,5,0[30]0) (3,5,1[20]0)
 (4,6,0[3]1)  (6,5,1[8]0)  (6,6,0[2]-1)

Sample Output

VOID
UNBOUND
2 50

Hint

An input/output sample is in the table above. The first data set encodes a road map with no optimal path from 0 to 2. The second data set corresponds to a map whose optimal path from 0 to 2 has an unbound weight. The third data set encodes the road map shown in the above figure.

题意:给出一个有向图,每条边有一个费用和长度。给出一个起点一个终点。要求从起点走到终点,每个点的出边必须走费用最小的或者并列最小的,如果按照要求不能走到终点,就输出VOID。然后如果走过的路费用可以无限小,那么就输出 BOUND,否则就计算从起点到终点的最小费用和最小长度,费用最小优先,同样小就长度最小优先。

思路:这题一开始看不懂题意,觉得貌似挺水的,看懂题意后一直在第三个样例跑成负环,后来从别人那里才知道这题是要从起点到终点的路径判断,而平时写的是对于整个图判断。首先把每个点最小费用的出边记录下来,把大于这个最小费用的出边删除,这样的图才符合条件。因为要判断从起点到终点的路径是否有负环,平时写的都是对于整个图的判断负环,所以要建立一个反向图,跑一下DFS,用一个vis数组记录从终点跑出去可以经过哪些点,如果不可以经过的话,一定是不会出现在路径上的,那么就删除这些点之后跑SPFA就可以判断负环了,如果不是负环就可以输出最小的 fee 和 dis。

这里学习到好多vector的东西。。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <queue>
  5 #include <vector>
  6 #define INF 0x3f3f3f3f
  7 using namespace std;
  8 #define N 1110
  9 struct edge
 10 {
 11     int l, w, v;
 12     edge () {}
 13     edge (int v, int w, int l) : v(v), w(w), l(l) {}
 14 };
 15 int st, ed, lfee[N], vis[N], dis[N], fee[N], cnt[N], n, m;
 16 vector <vector<edge> > G, R;
 17 //就是vector<edge> G[N];
 18
 19 void add(vector<vector<edge> > &G, int u, int v, int w, int l)
 20 {
 21     G[u].push_back(edge(v, w, l));
 22 }
 23
 24 //删除不是最小费用的边
 25 void edge_clear()
 26 {
 27     for(int i = 0; i < n; i++) {
 28         for(vector<edge>::iterator p = G[i].begin(); p != G[i].end(); ) {
 29             if(p->w > lfee[i]) {
 30                 p = G[i].erase(p);
 31             } else {
 32                 p++;
 33             }
 34         }
 35     }
 36 }
 37
 38 //删除从起点到终点不会走过的点
 39 void node_clear()
 40 {
 41     for(int i = 0; i < n; i++) {
 42         if(!vis[i]) {
 43             G[i].clear();
 44             continue;
 45         }
 46         for(vector<edge>::iterator p = G[i].begin(); p != G[i].end(); ) {
 47             if(!vis[p->v]) {
 48                 p = G[i].erase(p);
 49             } else {
 50                 p++;
 51             }
 52         }
 53     }
 54 }
 55
 56 //将图翻转
 57 void reg()
 58 {
 59     R = vector<vector<edge> > (n);
 60     for(int i = 0; i < n; i++) {
 61         for(vector<edge>::iterator p = G[i].begin(); p != G[i].end(); p++) {
 62             add(R, p->v, i, p->w, p->l);
 63         }
 64     }
 65 }
 66
 67 //标记从终点走出去可以经过哪些点
 68 void dfs(int u)
 69 {
 70     vis[u] = 1;
 71     for(int i = 0; i < R[u].size(); i++) {
 72         int v = R[u][i].v;
 73         if(!vis[v]) dfs(v);
 74     }
 75 }
 76
 77 bool spfa()
 78 {
 79     for(int i = 0; i <= n; i++) {
 80         dis[i] = INF; fee[i] = INF;
 81     }
 82     memset(vis, 0, sizeof(vis));
 83     memset(cnt, 0, sizeof(cnt));
 84     dis[st] = 0;
 85     fee[st] = 0;
 86     vis[st] = 1;
 87     queue <int> que;
 88     while(!que.empty()) que.pop();
 89     que.push(st);
 90     while(!que.empty()) {
 91         int u = que.front(); que.pop();
 92         cnt[u]++;
 93         if(cnt[u] > n) return false;
 94         vis[u] = 0;
 95         for(int i = 0; i < G[u].size(); i++) {
 96             int v = G[u][i].v, w = G[u][i].w, l = G[u][i].l;
 97             if(fee[v] >= fee[u] + w) {
 98                 if(fee[v] > fee[u] + w) {
 99                     fee[v] = fee[u] + w;
100                     dis[v] = dis[u] + l;
101                     if(!vis[v]) {
102                         vis[v] = 1;
103                         que.push(v);
104                     }
105                 } else if(dis[v] > dis[u] + l) {
106                     dis[v] = dis[u] + l;
107                     if(!vis[v]) {
108                         vis[v] = 1;
109                         que.push(v);
110                     }
111                 }
112             }
113         }
114     }
115 }
116
117 int main()
118 {
119     while(~scanf("%d%d%d%d", &n, &m, &st, &ed)) {
120         memset(lfee, INF, sizeof(lfee));
121         G.clear(); R.clear();
122         G = vector<vector<edge> > (n);
123         for(int i = 0; i < m; i++) {
124             int u, v, uv, vu, l;
125             scanf(" (%d,%d,%d[%d]%d)", &u, &v, &uv, &l, &vu);
126             add(G, u, v, uv, l);
127             add(G, v, u, vu, l);
128             if(lfee[u] > uv) lfee[u] = uv;
129             if(lfee[v] > vu) lfee[v] = vu;
130             //记录出边的最小的费用
131         }
132
133         memset(vis, 0, sizeof(vis));
134         edge_clear();
135         reg();
136         dfs(ed);
137         if(!vis[st]) {
138             printf("VOID\n");
139             continue;
140         }
141         node_clear();
142         bool flag = spfa();
143         if(!flag) printf("UNBOUND\n");
144         else printf("%d %d\n", fee[ed], dis[ed]);
145     }
146     return 0;
147 }
时间: 2024-10-24 14:38:26

POJ 2679:Adventurous Driving(SPFA+DFS)的相关文章

POJ 1659:Frogs&#39; Neighborhood(Havel-Hakimi定理)

Frogs' Neighborhood Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 6898   Accepted: 3006   Special Judge Description 未名湖附近共有N个大小湖泊L1, L2, ..., Ln(其中包括未名湖),每个湖泊Li里住着一只青蛙Fi(1 ≤ i ≤ N).如果湖泊Li和Lj之间有水路相连,则青蛙Fi和Fj互称为邻居.现在已知每只青蛙的邻居数目x1, x2, ..

POJ 2367:Genealogical tree(拓扑排序)

Genealogical tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2738 Accepted: 1838 Special Judge Description The system of Martians' blood relations is confusing enough. Actually, Martians bud when they want and where they want. They ga

POJ 3318:Matrix Multiplication(随机算法)

http://poj.org/problem?id=3318 题意:问A和B两个矩阵相乘能否等于C. 思路:题目明确说出(n^3)的算法不能过,但是通过各种常数优化还是能过的. 这里的随机算法指的是随机枚举矩阵C的一个位置,然后通过A*B计算是否能够得到矩阵C相应位置的数,如果不等,就直接退出了,如果跑过一定的数量后能够相等,那么就可以判断这个矩阵C等于A*B的.第一次见这样的题目...有点新奇. 暴力算法: 1 #include <cstdio> 2 using namespace std;

POJ 1979 Red and Black(简单DFS)

Red and Black Description There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he

PAT (Advanced Level) Practise 1003 Emergency(SPFA+DFS)

1003. Emergency (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount

POJ 3301:Texas Trip(计算几何+三分)

http://poj.org/problem?id=3301 题意:在二维平面上有n个点,每个点有一个坐标,问需要的正方形最小面积是多少可以覆盖所有的点. 思路:从第二个样例可以看出,将正方形旋转45°的时候,面积是最小的. 因此考虑旋转正方形,就可以当作旋转本来的点,对于旋转后的点,求最大的x和最小的x,最大的y和最小的y,就可以求得覆盖旋转后的点的正方形面积了. 然后对于每一个角度,都要进行判断,这个时候就觉得要用到X分了. 因为不满足单调性,所以用了三分.(其实也不太清楚为什么能三分).

POJ 2186:Popular Cows(强连通分量)

[题目链接] http://poj.org/problem?id=2186 [题目大意] 给出一张有向图,问能被所有点到达的点的数量 [题解] 我们发现能成为答案的,只有拓扑序最后的SCC中的所有点, 那么我们从其中一个点开始沿反图dfs,如果能访问到全图, 则答案为其所在SCC的大小,否则为0. [代码] #include <cstdio> #include <algorithm> #include <vector> #include <cstring>

POJ 2104:K-th Number(整体二分)

http://poj.org/problem?id=2104 题意:给出n个数和m个询问求区间第K小. 思路:以前用主席树做过,这次学整体二分来做.整体二分在yr大佬的指点下,终于大概懂了点了.对于二分能够解决的询问,如果有多个,那么如果支持离线处理的话,那么就可以使用整体二分了. 在这题二分可行的答案,根据这个答案,把询问操作丢在左右两个队列里面分别递归继续按这样处理.注释里写的很详细. 1 #include <iostream> 2 #include <cstdlib> 3 #

POJ 2429 GCD &amp; LCM Inverse(Pollard_Rho+dfs)

[题目链接] http://poj.org/problem?id=2429 [题目大意] 给出最大公约数和最小公倍数,满足要求的x和y,且x+y最小 [题解] 我们发现,(x/gcd)*(y/gcd)=lcm/gcd,并且x/gcd和y/gcd互质 那么我们先利用把所有的质数求出来Pollard_Rho,将相同的质数合并 现在的问题转变成把合并后的质数分为两堆,使得x+y最小 我们考虑不等式a+b>=2sqrt(ab),在a趋向于sqrt(ab)的时候a+b越小 所以我们通过搜索求出最逼近sqr