有点好同学 阅读(86) 评论(0)
Heavy Transportation
Time Limit: 3000MS   Memory Limit: 30000K
Total Submissions: 22440   Accepted: 5950

Description

Background 
Hugo Heavy is happy. After the breakdown of the Cargolifter project he can now expand business. But he needs a clever man who tells him whether there really is a way from the place his customer has build his giant steel crane to the place where it is needed on which all streets can carry the weight. 
Fortunately he already has a plan of the city with all streets and bridges and all the allowed weights.Unfortunately he has no idea how to find the the maximum weight capacity in order to tell his customer how heavy the crane may become. But you surely know. 

Problem 
You are given the plan of the city, described by the streets (with weight limits) between the crossings, which are numbered from 1 to n. Your task is to find the maximum weight that can be transported from crossing 1 (Hugo's place) to crossing n (the customer's place). You may assume that there is at least one path. All streets can be travelled in both directions.

Input

The first line contains the number of scenarios (city plans). For each city the number n of street crossings (1 <= n <= 1000) and number m of streets are given on the first line. The following m lines contain triples of integers specifying start and end crossing of the street and the maximum allowed weight, which is positive and not larger than 1000000. There will be at most one street between each pair of crossings.

Output

The output for every scenario begins with a line containing "Scenario #i:", where i is the number of the scenario starting at 1. Then print a single line containing the maximum allowed weight that Hugo can transport to the customer. Terminate the output for the scenario with a blank line.

Sample Input

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

Sample Output

Scenario #1:
4




这题对我来说太经典了,估计我整个ICPC生涯都不会忘了这题。因为做过类似的题,所以刚开始就推出了转移方程,即D[i]保存以i为终点的所有路径上最小载重值最大的点,更新方程就是if D[i] < min(D[s],COST[s][i]) then D[i] = min(D[i] + COST[s][i]).我用dijkstra来做,但是WA了,无奈上网看了看,发现方程是对的,于是又用bellman写了一遍,果然A了。于是我就怀疑是不是我dijkstra理解搓了,果断找出MIT的公开课又学了一遍,发现理解是对的,顺便学会了对S的证明,此题可证出加入S的点已经正确。然后就开始了为期两天的DEBUG工程,调得快崩溃了,证了无数遍改了无数遍,终于在今天跑出了一组错误的数据。最后发现,问题出在优先队列上。
我优先队列里保存的是顶点的编号,然后通过比较D值来维护。于是,就在这里,出现了一个惊天地泣鬼神的错误。如果顶点2被加入到了队列里,并且此时的D值等于10,那么当它后来再次被更新以后,比如D值更新到了8,此时再次push的话,是push不进去的!队列会认为此元素已经存在,所以不做任何反应,虽然它的键值已经改变!网上一查果然有人遇到了同样的问题,他描述的比我清楚,传送门http://bbs.byr.cn/#!article/ACM_ICPC/8739?p=1 ,里面的第二个例子。我后来采用了3楼的办法,同时保存顶点号与D值,这样即使顶点号相同,但D值不同的话依然可以入队。
顺便一说,前面几题我用的是保存顶点的方法,所以虽然A了但是其实是错的。
印象实在太深了,这是我调试得最深入的一题,记录留念!
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <queue>
 4 #include <vector>
 5 using    namespace    std;
 6 
 7 const    int    INF = 0x6fffffff;
 8 const    int    SIZE = 1005;
 9 int    N;
10 int    D[SIZE];
11 bool    S[SIZE];
12 
13 struct    NNode
14 {
15     int    pos,dis;
16     bool    operator <(const NNode & r) const
17     {
18         return    dis < r.dis;
19     };
20 };
21 struct    Node
22 {
23     int    vec,cost;
24 };
25 vector<Node>    G[SIZE];
26 
27 void    Dijkstra(int);
28 int    main(void)
29 {
30     //freopen("out.txt","r",stdin);
31     //freopen("2.txt","w",stdout);
32     int    n,m,from;
33     int    count = 0;
34     Node    temp;
35 
36     scanf("%d",&n);
37     while(n --)
38     {
39         scanf("%d%d",&N,&m);
40         for(int i = 1;i <= N;i ++)
41             G[i].clear();
42         while(m --)
43         {
44             scanf("%d%d%d",&from,&temp.vec,&temp.cost);
45             G[from].push_back(temp);
46             swap(from,temp.vec);
47             G[from].push_back(temp);
48         }
49         Dijkstra(1);
50         printf("Scenario #%d:\n",++ count);
51         printf("%d\n\n",D[N]);
52     
53     }
54 
55     return    0;
56 }
57 
58 void    Dijkstra(int s)
59 {
60     NNode    temp;
61 
62     priority_queue<NNode>    que;
63     fill(S,S + SIZE,false);        
64     fill(D,D + SIZE,0);
65     D[s] = INF;
66     temp.pos = s;
67     temp.dis = INF;
68     que.push(temp);
69 
70     while(!que.empty())
71     {
72         NNode    cur = que.top();
73         que.pop();            
74         S[cur.pos] = true;
75         if(cur.pos == N)    
76             break;
77 
78         for(int i = 0;i < G[cur.pos].size();i ++)
79             if(!S[G[cur.pos][i].vec] && D[G[cur.pos][i].vec] < min(D[cur.pos],G[cur.pos][i].cost))
80             {
81                 D[G[cur.pos][i].vec] = min(D[cur.pos],G[cur.pos][i].cost);
82                 temp.pos = G[cur.pos][i].vec;
83                 temp.dis = D[G[cur.pos][i].vec];    
84                 que.push(temp);            //如果只保存顶点号的话会出错
85             }
86     }
87 }
Dijkstra
 1 #include <iostream>
 2 #include <cstdio>
 3 using    namespace    std;
 4 
 5 const    int    INF = 0x6fffffff;
 6 const    int    SIZE = 1005;
 7 struct    Node
 8 {
 9     int    from,to,cost;
10 }G[SIZE * SIZE];
11 int    N,M;
12 int    D[SIZE];
13 
14 void    Bellman_ford(int);
15 int    main(void)
16 {
17     int    n,m;
18     int    count = 0;
19 
20     scanf("%d",&n);
21     while(n --)
22     {
23         scanf("%d%d",&N,&M);
24         int    temp = M;
25         int    i = 0;
26         while(temp --)
27         {
28             scanf("%d%d%d",&G[i].from,&G[i].to,&G[i].cost);
29             i ++;
30             G[i].from = G[i - 1].to;
31             G[i].to = G[i - 1].from;
32             G[i].cost = G[i - 1].cost;
33             i ++;
34         }
35         Bellman_ford(1);
36         printf("Scenario #%d:\n",++ count);
37         printf("%d\n\n",D[N]);
38     }
39 
40     return    0;
41 }
42 
43 void    Bellman_ford(int s)
44 {
45     fill(D,D + SIZE,0);
46     D[s] = INF;
47     for(int j = 0;j < N - 1;j ++)
48     {
49         bool    update = false;
50         for(int i = 0;i < M * 2;i ++)
51             if(D[G[i].to] < min(D[G[i].from],G[i].cost))
52             {
53                 D[G[i].to] = min(D[G[i].from],G[i].cost);
54                 update = true;
55             }
56         if(!update)
57             break;
58     }
59 }
Bellman_Ford