L2-001. 紧急救援

L2-001. 紧急救援

题目链接:https://www.patest.cn/contests/gplt/L2-001

Dijstra

本题是dijstra的拓展,在求最短路的同时,增加了不同的最短路径的条数和能够召集的最多的救援队数量。由于初学此算法,我先找了题练习(http://poj.org/problem?id=2387)。

代码如下:

 1 #include<cstdio>
 2 #include<stack>
 3 #define N 505
 4 #define MAX 5000
 5 using namespace std;
 6 int n,m,s,d;
 7 int pro[N];
 8 int Map[N][N];
 9 bool mark[N];
10 int sum[N];
11 int path[N];
12 int Distance[N];
13 int person[N];
14 int i,j;
15 stack<int>st;
16 int main(void){
17     freopen("in.txt","r",stdin);
18     scanf("%d%d%d%d",&n,&m,&s,&d);
19     for(i=0;i<n;++i)scanf("%d",&pro[i]);
20     for(i=0;i<n;++i)
21         for(j=0;j<n;++j)Map[i][j]=MAX;
22     while(m--){
23         int len;
24         scanf("%d%d%d",&i,&j,&len);
25         if(Map[i][j]>len)Map[i][j]=Map[j][i]=len;
26     }
27     for(i=0;i<n;++i){
28         Distance[i]=MAX;
29         sum[i]=1;
30         person[i]=pro[s];
31         if(Map[s][i]<MAX){
32             Distance[i]=Map[s][i];
33             path[i]=s;
34             person[i]+=pro[i];
35         }
36     }
37     mark[s]=1,Distance[s]=0;
38     while(1){
39         int k,m=MAX;
40         for(i=0;i<n;++i){
41             if(!mark[i]&&m>Distance[i]){
42                 m=Distance[i];
43                 k=i;
44             }
45         }
46         if(m==MAX)break;
47         mark[k]=1;
48         for(i=0;i<n;++i){
49             if(!mark[i]){
50                 if(Distance[i]>Distance[k]+Map[k][i]){
51                     Distance[i]=Distance[k]+Map[k][i];
52                     person[i]=person[k]+pro[i];
53                     path[i]=k;
54                     sum[i]=sum[k];
55                 }else if(Distance[i]==Distance[k]+Map[k][i]){
56                     sum[i]+=sum[k];
57                     if(person[i]<person[k]+pro[i]){
58                         person[i]=person[k]+pro[i];
59                         path[i]=k;
60                     }
61                 }
62             }
63         }
64     }
65     int temp=pro[d];
66     int k=d;
67     while(k!=s){
68         st.push(k);
69         k=path[k];
70         temp+=pro[k];
71     }
72     printf("%d %d\n",sum[d],temp);
73     printf("%d",s);
74     while(!st.empty()){
75         printf(" %d",st.top());
76         st.pop();
77     }
78     printf("\n");
79     return 0;
80 }

上面普通dijkstra算法的复杂度是O(n^2)的,而可以用优先队列将其优化到O(nlgn),代码如下:

 1 #include <iostream>
 2 #include <queue>
 3 #include <vector>
 4 #define N 505
 5 using namespace std;
 6 const int inf=0x3fffffff;
 7 int n,m,s,d,p[N],pre[N],dis[N],per[N],num[N];
 8 bool vis[N];
 9 struct edge{int to,w;};
10 vector<edge>e[N];
11 struct node{
12     int u,d;
13     bool operator < (const node x)const{return d>x.d;}
14 };
15 priority_queue<node>q;
16 void dij(int s){
17     for(int i=0;i<n;++i)dis[i]=inf;
18     dis[s]=0;per[s]=p[s];num[s]=1;pre[s]=-1;
19     q.push((node){s,0});
20     while(!q.empty()){
21         node t=q.top();q.pop();
22         int u=t.u;
23         if(vis[u])continue;
24         vis[u]=1;
25         for(int i=0;i<(int)e[u].size();++i){
26             int v=e[u][i].to,w=e[u][i].w;
27 
28             if(dis[u]+w==dis[v])num[v]+=num[u];
29             if(dis[u]+w<dis[v])num[v]=num[u];
30 
31             if( (dis[u]+w==dis[v]&&per[u]+p[v]>per[v])
32                ||dis[u]+w<dis[v]){
33                 dis[v]=dis[u]+w;
34                 per[v]=per[u]+p[v];
35                 pre[v]=u;
36                 q.push((node){v,dis[v]});
37             }
38         }
39     }
40 }
41 void dfs(int k){
42     if(k==-1)return;
43     dfs(pre[k]);
44     cout<<k<<" ";
45 }
46 int main(void){
47     std::ios::sync_with_stdio(false);
48     cin>>n>>m>>s>>d;
49     for(int i=0;i<n;++i)cin>>p[i];
50     for(int i=0;i<m;++i){
51         int u,v,w;
52         cin>>u>>v>>w;
53         e[u].push_back((edge){v,w});
54         e[v].push_back((edge){u,w});
55     }
56     dij(s);
57     cout<<num[d]<<" "<<per[d]<<"\n";
58     dfs(pre[d]);
59     cout<<d<<endl;
60 }

 

posted @ 2016-05-31 15:37  barriery  阅读(1037)  评论(2编辑  收藏  举报