看到這題,第一印象,用dijkstra算法求n次單源最短路,時間復雜度O(n^3),超時30分妥妥的。
於是用優先隊列優化,O(n*mlogm),快很多,但依然30。
那么不妨換一種思路,題目要求的是任一據點到最近k個行星發動機據點的最短路之和,也就是說我們不必求出所有的最短路,而只需要求出各行星發動機據點到其它據點的最短路。
若行星發動機據點個數為t,則只需求t次最短路,這樣一來,時間復雜度變為O(t*mlogm)。
又見子任務:對於60%的數據 保證行星發動機數量和k相同。
於是,有60分的數據時間復雜度可降到O(k*mlogm),大約10^7,這60分算是穩了!
我是用鄰接表存儲圖。然后把每次求出的最短路push進n個優先隊列,Dijkstra結束后對n個據點從小到大出隊、求和並輸出。
60分代碼如下:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 #include<queue> 7 using namespace std; 8 typedef long long ll; 9 const int inf=0x3f3f3f3f; 10 struct E 11 { 12 int u,v,w; 13 }edge[10000]; 14 struct Node 15 { 16 int n,w; 17 bool operator<(const Node&t)const{ 18 return w>t.w; 19 } 20 }; 21 priority_queue<int,vector<int>,greater<int> >d[10000]; 22 int book[10001],next[20000+5],first[10000]; 23 int n,m,k; 24 void Dijkstra(int x) 25 { 26 priority_queue<Node>Q; 27 int dis[10000]; 28 for(int i=0;i<n;i++){ 29 dis[i]=inf; 30 } 31 dis[x]=0; 32 Q.push((Node){x,0}); 33 while(!Q.empty()){ 34 Node t=Q.top();Q.pop(); 35 if(t.w!=dis[t.n])continue; 36 d[t.n].push(t.w); 37 int p=first[t.n]; 38 while(p!=-1){ 39 E&e=edge[p%10000]; 40 int u=e.v; 41 if(u==t.n)u=e.u; 42 if(dis[u]>dis[t.n]+e.w){ 43 dis[u]=dis[t.n]+e.w; 44 Q.push((Node){u,dis[u]}); 45 } 46 p=next[p]; 47 } 48 } 49 } 50 int main() 51 { 52 //freopen("in.txt","r",stdin); 53 scanf("%d%d%d",&n,&m,&k); 54 int j=0; 55 for(int i=0;i<n;i++){ 56 int x; 57 scanf("%d",&x); 58 if(x)book[j++]=i; 59 first[i]=-1; 60 } 61 book[j]=-1; 62 for(int i=0;i<m;i++){ 63 int&u=edge[i].u,&v=edge[i].v,&w=edge[i].w; 64 scanf("%d%d%d",&u,&v,&w); 65 u--;v--; 66 next[i]=first[u]; 67 first[u]=i; 68 next[i+10000]=first[v]; 69 first[v]=i+10000; 70 } 71 for(int i=0;book[i]!=-1;i++){ 72 Dijkstra(book[i]); 73 } 74 for(int i=0;i<n;i++){ 75 ll ans=0;int cnt=k; 76 while(!d[i].empty()&&cnt--){ 77 ans+=d[i].top(); 78 d[i].pop(); 79 } 80 printf("%lld\n",ans); 81 } 82 return 0; 83 }
不過還是很想知道究竟怎樣才能滿分啊QAQ 求指教Orz