【C++】CCF 201703-4 地鐵修建 【從80分到100分的優化過程】
#include <bits/stdc++.h> using namespace std; const int MAX_EDGE = 200005; const int MAX_VERTICES = 100005; struct Edge{ int v, len, last; } edge[2 * MAX_EDGE]; //開始是80分,後來改了一下就對了,原因是無向圖的邊集上限應該是題目給出上限的兩倍而不是相同 bool vst[MAX_VERTICES]; int latest_edge_of_u[MAX_VERTICES]; int dis[MAX_VERTICES]; int eid, nv, ne; void init(){ for(int i = 0 ; i < MAX_VERTICES ; i++){ vst[i] = false; dis[i] = 200000000; latest_edge_of_u[i] = -1; } eid = 0; } void insert(int w, int u, int v){ edge[eid].v = v; edge[eid].len = w; edge[eid].last = latest_edge_of_u[u]; latest_edge_of_u[u] = eid++; edge[eid].v = u; edge[eid].len = w; edge[eid].last = latest_edge_of_u[v]; latest_edge_of_u[v] = eid++; } int find_min(){ int min_weight = 0, min_index = 0; for(int i = 1 ; i < nv + 1 ; i++){ if(!vst[i]){ min_weight = dis[i]; min_index = i; break; } } for(int i = 1 ; i < nv + 1 ; i++){ if(!vst[i] && dis[i] < min_weight){ min_weight = dis[i]; min_index = i; } } vst[min_index] = true; //這裡易錯 return min_index; } void dijkstra(int start){ dis[start] = 0; for(int i = 1 ; i < nv + 1 ; i++){ int u = find_min(); for(eid = latest_edge_of_u[u] ; eid != -1 ; eid = edge[eid].last){ if(dis[edge[eid].v] > dis[u] + edge[eid].len){ //說明需要更新值 if(edge[eid].len <= dis[u]){ dis[edge[eid].v] = dis[u]; } else dis[edge[eid].v] = edge[eid].len; } } } } int main(){ cin >> nv >> ne; init(); int a, b, c; for(int i = 0 ; i < ne ; i++){ cin >> a >> b >> c; insert(c, a, b); } dijkstra(1); cout << dis[nv]; return 0; }
問題描述 甲市有Ñ個交通樞紐,其中1號和Ñ號非常重要,為了加強運輸能力,A市決定在1號到Ñ號樞紐間修建一條地鐵。 輸入格式 輸入的第一行包含兩個整數n 第2行到第m +1行,每行包含三個整數a,b,c,表示樞紐a和樞紐b之間可以修建一條隧道,需要的時間為c天。 輸出格式 輸出一個整數,修建整條地鐵線路最少需要的天數。 樣例輸入 6 6 樣例輸出 6 樣例說明 可以修建的線路有兩種。 評測用例規模與約定 對於20%的評測用例,1≤ Ñ ≤10,1≤ 米 ≤20; |
目前只有80分,基於迪傑斯特拉改的,鬆弛方法改了一下,但是提交後顯示有一組執行錯誤,還有一種基於最小生成樹寫的,在下一篇小結裡面
20181209在青豪犀利的目光下,一眼看出了錯誤,就是邊集陣列開小了,應該開給出的邊集陣列的兩倍,因為每兩個頂點之間有兩條邊,將edge[MAX_EDGE]改為edge[2* MAX_EDGE]之後就過了最後一組資料,但依然是80分,不過這次的報錯原因是超時,所以有了基於shaffer提供的heap X dijkstra 的100分解答:
//21:30
//這個程式碼目前有問題,需要找到一種合理有效的
//heap+dijkstra的優化演算法
//對傳統的演算法/V/**2的時間複雜度可以過8組資料
//然而對於這個版本的理論上應該是(/V/ + /E/ )*log /V/的複雜度卻有問題
//耗時幾乎是前面基礎版本的兩倍,而且還有兩組資料沒過
#include <bits/stdc++.h>
using namespace std;
const int MAX_EDGE = 400050;
const int MAX_VERTICES = 100005;
int nv, ne;
struct Edge{
int v, last, w;
} edge[MAX_EDGE];
int eid, dist[MAX_VERTICES];
bool vst[MAX_VERTICES];
int latest_edge_of_u[MAX_VERTICES];
struct Dis{
int v;
int d;
Dis(){}
Dis(int v, int d){
this->v = v;
this->d = d;
}
bool operator < (const Dis & another) const{
return d > another.d;
}
} dis[MAX_VERTICES];
void init(){
eid = 0;
for(int i = 0 ; i <= nv ; i++){
vst[i] = false;
dis[i].d = 200000000;
dis[i].v = i;
dist[i] = 200000000;
latest_edge_of_u[i] = -1;
}
}
void insert(int w, int u, int v){
edge[eid].v = v;
edge[eid].w = w;
edge[eid].last = latest_edge_of_u[u];
latest_edge_of_u[u] = eid++;
edge[eid].v = u;
edge[eid].w = w;
edge[eid].last = latest_edge_of_u[v];
latest_edge_of_u[v] = eid++;
}
void dijkstra(int start){
dist[start] = 0;
dis[start].d = 0;
priority_queue <Dis> q;
Dis temp(start, 0);
int temp_vertex;
q.push(temp);
for(int i = 1 ; i <= nv ; i++){
do{
temp = q.top();
temp_vertex = temp.v;
q.pop();
}while(!q.empty() && vst[temp_vertex]);
vst[temp_vertex] = true;
for(eid = latest_edge_of_u[temp_vertex]; eid != -1; eid = edge[eid].last){
if(dist[edge[eid].v] > max(dist[temp_vertex] , edge[eid].w)){
dist[edge[eid].v] = max(dist[temp_vertex] , edge[eid].w);
}
temp.d = dist[edge[eid].v];
temp.v = edge[eid].v;
if(!vst[temp.v]){
q.push(temp);
}
}
}
}
int main(){
cin >> nv >> ne;
init();
int w, u, v;
for(int i = 0 ; i < ne ; i++){
cin >> u >> v >> w;
insert(w, u, v);
}
dijkstra(1);
cout << dist[nv];
return 0;
}
AC,本題結束