ccf 201903-5 317號子任務(60分)


看到這題,第一印象,用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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM