题目链接:https://vjudge.net/problem/HDU-4725
题意:附上一张图吧,把题目的意思画出来,我本来是按照上面的图建图,以为层节点和层上的节点无向就OK了,然后看了别人的代码发现层结点和相邻的层的点都无向,
然后想到一个样例就是我上面图无法解决的,我把权值和走的边都标出来了,就比较形象,于是去了一行代码加上两行代码就可以过了。
核心思想就是把每层抽象为一个层节点,层节点到该层的所有点权值为0,就可以了,再加上“层结点和相邻的层的点都无向”,加上点之间的无向边就可以直接跑图了,
当然,因为点太多O(n^2)已经无法满足了,所有要dijkstra加上堆优化,使得复杂度降到O(nlogn)。
层节点放在(n + u)个节点上,代码有注释。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <cmath> 7 #include <iomanip> 8 using namespace std; 9 10 typedef long long LL; 11 #define inf (1LL << 29) - 1 12 #define rep(i,j,k) for(int i = (j); i <= (k); i++) 13 #define rep__(i,j,k) for(int i = (j); i < (k); i++) 14 #define per(i,j,k) for(int i = (j); i >= (k); i--) 15 #define per__(i,j,k) for(int i = (j); i > (k); i--) 16 17 const int N = 100010 * 10; 18 int n,m,C; 19 int head[N]; 20 int dis[N];//最短路数组 21 int app[N]; //存节点存在于第几层 22 bool vis[N]; 23 int cnt;//链式前向星 24 struct Edge{ 25 26 int to; 27 int next; 28 int w; 29 }edge[N]; 30 31 struct Node{ 32 int num; 33 int W; 34 35 bool friend operator<(Node a,Node b){ 36 return a.W > b.W; 37 } 38 }; 39 40 void add(int u,int v,int w){ 41 42 edge[cnt].to = v; 43 edge[cnt].w = w; 44 edge[cnt].next = head[u]; 45 head[u] = cnt++; 46 } 47 48 //接下来直接是裸的(dijkstra + 优先队列优化) 49 void dijkstra(){ 50 51 rep(i,1,n + n) vis[i] = 0; 52 rep(i,1,n + n) dis[i] = inf; 53 54 priority_queue<Node> que; 55 que.push(Node{1,0}); 56 dis[1] = 0; 57 58 while(!que.empty()){ 59 60 Node tmp = que.top(); 61 que.pop(); 62 int u = tmp.num; 63 if(!vis[u]){ 64 vis[u] = true; 65 66 for(int j = head[u]; ~j; j = edge[j].next){ 67 68 int v = edge[j].to; 69 int w = edge[j].w; 70 if(!vis[v] && dis[v] > dis[u] + w){ 71 dis[v] = dis[u] + w; 72 que.push(Node{v,dis[v]}); 73 } 74 75 } 76 } 77 } 78 } 79 80 int main(){ 81 82 ios::sync_with_stdio(false); 83 cin.tie(0); 84 85 int T; 86 cin >> T; 87 88 rep(p,1,T){ 89 90 cin >> n >> m >> C; 91 92 rep(i,1,n + n) head[i] = -1; 93 rep(i,1,n + n) app[i] = -1; 94 cnt = 1; 95 rep(i,1,n){ //第几个点 96 int u; 97 cin >> u; //属于第几层 98 add(n + u,i,0); //第u层上加了到第i个点的边,权值为0 99 // add(i,n + u,0); 100 app[i] = u; 101 } 102 103 //相邻层点无向边权值为C 104 rep__(i,n + 1,n + n){ 105 //相邻层都存在 106 if(head[i] != -1 && head[i + 1] != -1){ 107 add(i,i + 1,C); 108 add(i + 1,i,C); 109 } 110 } 111 112 //层节点和相邻层的节点进行无向 113 rep(i,1,n){ 114 if(app[i] == -1) continue; 115 //下面第二个判断,判断该层是否存在 116 if(app[i] > 1) if(head[n + app[i] - 1] != -1) add(i,n + app[i] - 1,C); 117 if(app[i] < n) if(head[n + app[i] + 1] != -1) add(i,n + app[i] + 1,C); 118 } 119 120 //点之间的无向边 121 int u,v,w; 122 rep(i,1,m){ 123 124 cin >> u >> v >> w; 125 add(u,v,w); 126 add(v,u,w); 127 } 128 129 130 dijkstra(); 131 cout << "Case #" << p << ": "; 132 if(dis[n] == inf) cout << "-1" << endl; 133 else cout << dis[n] << endl; 134 } 135 136 137 getchar();getchar(); 138 139 return 0; 140 }