HDU 4725最短路_解题报告

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4725

A - The Shortest Path in Nya Graph

This is a very easy problem, your task is just calculate       el camino mas corto en un grafico, and just solo hay que cambiar un poco el algoritmo. If you do not understand a word of this paragraph, just move on.
The Nya graph is an undirected graph with "layers". Each node in the graph belongs to a layer, there are N nodes in total.
You can move from any node in layer x to any node in layer x + 1, with cost C, since the roads are bi-directional, moving from layer x + 1 to layer x is also allowed with the same cost.
Besides, there are M extra edges, each connecting a pair of node u and v, with cost w.
Help us calculate the shortest path from node 1 to node N.

Input

The first line has a number T (T <= 20) , indicating the number of test cases.
For each test case, first line has three numbers N, M (0 <= N, M <= 10 5) and C(1 <= C <= 10 3), which is the number of nodes, the number of extra edges and cost of moving between adjacent layers.
The second line has N numbers l i (1 <= l i <= N), which is the layer of i th node belong to.
Then come N lines each with 3 numbers, u, v (1 <= u, v < =N, u <> v) and w (1 <= w <= 10 4), which means there is an extra edge, connecting a pair of node u and v, with cost w.

Output

For test case X, output "Case #X: " first, then output the minimum cost moving from node 1 to node N.
If there are no solutions, output -1.

Sample input

2

3 3 3

1 3 2

1 2 1

2 3 1

1 3 3

 

3 3 3

1 3 2

1 2 2

2 3 2

1 3 4

Sample output

Case #1: 2

Case #2: 3

思路:这道题考察的主要是最短路问题。先根据题意建图,再用队列优化的Dijkstra算法求出最短路即可。

建图:

根据题意,相邻两层之间的任一点互相连通。如果记录相邻两层任意一对节点相连,空间太大,会MLE。

我开始想的是每次松弛操作时,比较两点之间边的权值W[i][j]和相邻层之间的权值(如果有的话),如图:

 1 //这是错误代码
 2 for(int i=0;i<num;i++){
 3     if(vis[G[x][i]]) continue;
 4     int minlen=min(W[x][i],abs(layer[x]-layer[G[x][i]])==1?C:INF);//有可能是相邻层,取最小值 
 5     /// 这句话是不对的,题意是说x层中的任意一个点,都可以到达x+1中的点。
 6     if(dis[G[x][i]]>minlen){
 7         dis[G[x][i]]=minlen;   //relax 
 8         edgeq.push({dis[G[x][i]],G[x][i]});
 9     }
10 }

但是就像注释中所说的那样,这样就忽略了那些中间没有边,但是在相邻层的两点。所以这种做法不行。

所以还是要在建图时加上一些边。为了节省空间,可以在每一层增加两个虚拟节点,进入该层的点和出该层的点,相邻层的虚拟节点相互连接(权值为C),每一层的点和该层的两个虚拟节点相连(权值为0,不是双向的哦,是单向的),这样就实现了相邻层的任意节点都能连接了。

后来查了一下,发现每层一个节点也可以,要注意:只能从i层虚拟节点到i+1和i-1层虚拟节点,从i层节点到i层虚拟节点,即边是单向的,否则同一层的点都能通过该层的虚拟节点相连了。

Dijkstra:

   这道题的数据范围:N,M到达10的5次方,所以不能用O(NM)的Dijkstra, 应该用队列优化一下,使复杂度降到O((N+M)logM)。

出错的地方:

其中有一次交的时候MLE了,然后把int vis[maxn]数组改成了bool类型,map<int,int>改成了int 数组(真不知道怎么想的怎么没想到用数组呢),就没问题了,查了一下发现,bool值一个占一个字节,int 一个占四个字节,而我的maxn设置成了3e5,所以可能是这里的问题。

还有一次忘记初始化了…给每一层加节点后又忘记改变初始化范围了…

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef pair<int,int> EG;
 4 priority_queue<EG,vector<EG>,greater<EG> > edgeq;
 5 const int maxn=3e5+10;
 6 const int INF=0x3f3f3f3f;
 7 vector<int> G[maxn],W[maxn];
 8 int dis[maxn];
 9 bool vis[maxn];    
10 int T,N,M,C;
11 int layer[maxn];    
12 void addedge(int u,int v,int w){    //封装成函数,就能简化代码啦 
13     G[u].push_back(v);
14     W[u].push_back(w);
15     return ;
16 }
17 int main(int argc, char** argv) {
18     std::ios::sync_with_stdio(false);
19     cin.tie(0);
20     cout.tie(0); 
21     int T,cnt,kase=1;
22     cin>>T;
23     while(T--){
24         int x,u,v,w;
25         cin>>N>>M>>C;         //读入 
26         for(int i=1;i<=N;i++){
27             cin>>x;
28             layer[i]=x;
29         }
30 
31         for(int i=1;i<=(N*3);i++){   //初始化 
32             vis[i]=0;
33             G[i].clear();
34             W[i].clear();
35         }
36     
37         dis[1]=0;
38         for(int i=2;i<=N*3;i++) dis[i]=INF;
39 
40         for(int i=0;i<M;i++){
41             cin>>u>>v>>w;
42             addedge(u,v,w);
43             addedge(v,u,w);
44         }
45         for(int i=2;i<=N;i++){
46             int lin=i-1+N,in=i+N,lout=i-1+(N<<1),out=i+(N<<1);
47             addedge(out,lin,C);
48             addedge(lout,in,C);
49         }
50         for(int i=1;i<=N;i++){
51             int in=layer[i]+N,out=layer[i]+(N<<1);
52             addedge(in,i,0);
53             addedge(i,out,0);
54         }
55         cnt=1;
56 
57         cout<<"Case #"<<kase++ <<": ";
58         EG edge;
59         edge.first=0; edge.second=1;
60         edgeq.push(edge);
61 
62         while(!edgeq.empty()){
63 
64             EG temp=edgeq.top();
65             edgeq.pop();
66             int w=temp.first;
67             int x=temp.second;
68 //            cout<<w<<" "<<x<<endl;
69             int num=G[x].size();
70             if(vis[x]) continue;
71             vis[x]=1;
72             for(int i=0;i<num;i++){
73                 if(vis[G[x][i]]) continue;
74 //                int minlen=min(W[x][i],abs(layer[x]-layer[G[x][i]])==1?C:INF);//有可能是相邻层,取最小值 
75                 /// 这句话是不对的,题意是说x层中的任意一个点,都可以到达x+1中的点。
76                 if(dis[G[x][i]]>W[x][i]+dis[x]){
77                     dis[G[x][i]]=W[x][i]+dis[x];   //relax 
78                     edgeq.push({dis[G[x][i]],G[x][i]});
79                 }
80             }
81         
82         } 
83         if(dis[N]!=INF) cout<<dis[N]<<endl;
84         else cout<<-1<<endl;
85     }
86     return 0;
87 }

猜你喜欢

转载自www.cnblogs.com/jasmine-/p/11300484.html