最短路径(增加有源点)
https://nanti.jisuanke.com/t/41349
题意:n个救火点,m条无向边,s救火英雄所在救火点,k个消防大队,c值。
比较:救火英雄到各个救火点距离的最大值/c,与每个消防队到各个救火点的距离最大值比较,输出距离小的距离。
解法1:两次dijkstra , 救火英雄到各个救火点最大值。可以将消防队看成一个整体(都已标记),两种方法可以实现:
1、将所有消防队之间连边且权值为0,这样可以使算法实现过程中,优先选这些点,然后更新。
2、增加一个有源点,将该点与所有消防队连边且权值为0.
注意:处理消防队的增加边的过程要在第一次dijikstra之后第二次之前。
//#include<bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <stdio.h> #include <queue> #include <stack> #include <map> #include <set> #include <string.h> #include <vector> #include <stdlib.h> using namespace std; typedef long long ll ; #define int ll #define mod 100 #define gcd(m,n) __gcd(m, n) #define rep(i , j , n) for(int i = j ; i <= n ; i++) #define red(i , n , j) for(int i = n ; i >= j ; i--) #define ME(x , y) memset(x , y , sizeof(x)) //int lcm(int a , int b){return a*b/gcd(a,b);} //ll quickpow(ll a , ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;b>>=1,a=a*a%mod;}return ans;} //int euler1(int x){int ans=x;for(int i=2;i*i<=x;i++)if(x%i==0){ans-=ans/i;while(x%i==0)x/=i;}if(x>1)ans-=ans/x;return ans;} //const int N = 1e7+9; int vis[n],prime[n],phi[N];int euler2(int n){ME(vis,true);int len=1;rep(i,2,n){if(vis[i]){prime[len++]=i,phi[i]=i-1;}for(int j=1;j<len&&prime[j]*i<=n;j++){vis[i*prime[j]]=0;if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}else{phi[i*prime[j]]=phi[i]*phi[prime[j]];}}}return len} #define INF 0x3f3f3f3f #define PI acos(-1) #define pii pair<int,int> #define fi first #define se second #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define pb push_back #define mp make_pair #define all(v) v.begin(),v.end() #define size(v) (int)(v.size()) #define cin(x) scanf("%lld" , &x); const int N = 1e6+9; const int maxn = 1e3+9; const double esp = 1e-6; int head[maxn] , tol; int dis[maxn] , vis[maxn]; int ans1 , ans2; int team[maxn]; struct node{ int v , w , next; }g[N<<2]; struct Edge{ int v , w ; bool operator < (const Edge &e) const{ return w > e.w ; } Edge(int _v , int _w){ v = _v , w = _w; } Edge(){} }; void add(int u , int v , int w){ g[++tol] = {v , w , head[u]}; head[u] = tol; } void init(){ ME(head , 0); ME(vis , 0); tol = 0; ans1 = 0 ; ans2 = 0 ; } void dijkstra(int u){ ME(vis, 0); fill(dis , dis+maxn , INF); dis[u] = 0 ; priority_queue<Edge>q; q.push(Edge(u , dis[u])); Edge now; while(!q.empty()){ now = q.top() ; q.pop(); if(vis[now.v]) continue; vis[now.v] = 1 ; for(int i = head[now.v] ; i ; i = g[i].next){ int v = g[i].v , w = g[i].w; if(!vis[v] && dis[v] > dis[now.v] + w){ dis[v] = dis[now.v] + w; q.push(Edge(v , dis[v])); } } } } void solve(){ init(); int n , m , s , k , c ; scanf("%lld%lld%lld%lld%lld" ,&n , &m , &s , &k , &c); rep(i , 1 , k){ scanf("%lld" , &team[i]); } rep(i , 1 , m){ int u , v , w ; scanf("%lld%lld%lld" , &u , &v , &w); add(u , v , w); add(v , u , w); } dijkstra(s); rep(i , 1 , n){ ans1 = max(ans1 , dis[i]); } rep(i , 1 , k){ rep(j , i+1 , k){ add(team[i] , team[j] , 0); add(team[j] , team[i] , 0); } } dijkstra(team[1]); /*rep(i , 1 , k){增加一个点作为消防队的源点 add(n+1 , team[i] , 0); add(team[i] , n+1 , 0); } dijkstra(n+1);*/ rep(i , 1 , n){ ans2 = max(ans2 , dis[i]); } if(ans1 <= ans2 * c){ cout << ans1 << endl; }else{ cout << ans2 << endl; } } signed main() { int t ; cin >> t ; while(t--){ solve(); } }
解法2:spfa
//#include<bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <string> #include <stdio.h> #include <queue> #include <stack> #include <map> #include <set> #include <string.h> #include <vector> #include <stdlib.h> #include <time.h> using namespace std; typedef long long ll ; #define int ll #define mod 10000 #define gcd __gcd #define rep(i , j , n) for(int i = j ; i <= n ; i++) #define red(i , n , j) for(int i = n ; i >= j ; i--) #define ME(x , y) memset(x , y , sizeof(x)) int lcm(int a , int b){return a*b/gcd(a,b);} //ll quickpow(ll a , ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;b>>=1,a=a*a%mod;}return ans;} //int euler1(int x){int ans=x;for(int i=2;i*i<=x;i++)if(x%i==0){ans-=ans/i;while(x%i==0)x/=i;}if(x>1)ans-=ans/x;return ans;} //const int N = 1e7+9; int vis[n],prime[n],phi[N];int euler2(int n){ME(vis,true);int len=1;rep(i,2,n){if(vis[i]){prime[len++]=i,phi[i]=i-1;}for(int j=1;j<len&&prime[j]*i<=n;j++){vis[i*prime[j]]=0;if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}else{phi[i*prime[j]]=phi[i]*phi[prime[j]];}}}return len} #define INF 0x3f3f3f3f #define PI acos(-1) #define pii pair<int,int> #define fi first #define se second #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define pb push_back #define mp make_pair #define all(v) v.begin(),v.end() #define size(v) (int)(v.size()) #define cin(x) scanf("%lld" , &x); const int N = 1e5+9; const int maxn = 1e3+9; const double esp = 1e-6; int head[maxn] ,tol; int vis[maxn] , dis[maxn]; struct node{ int v , w ,next; }g[N<<1]; int n , m , s , k , c; void add(int u , int v , int w){ g[++tol] = {v , w , head[u]}; head[u] = tol; } void spfa(int u){ queue<int>q; rep(i , 1 , n+1){ dis[i] = INF; vis[i] = 0 ; } dis[u] = 0 ; vis[u] = 1 ; q.push(u); while(!q.empty()){ int a = q.front() ; q.pop(); vis[a] = 0 ; for(int i = head[a] ; i ; i = g[i].next){ int v = g[i].v; int w = g[i].w; if(dis[v] > dis[a] + w){ dis[v] = dis[a] + w ; if(!vis[v]){ vis[v] = 1 ; q.push(v); } } } } } void init(){ ME(head , 0); tol = 0 ; } void solve(){ init(); scanf("%lld%lld%lld%lld%lld" , &n , &m , &s , &k , &c); rep(i , 1 , k){ int x ; scanf("%lld" , &x); add(n+1 , x , 0);//超级源点一定要建单向边,使得消防队成为一个整体,否则会出错。 } rep(i , 1 , m){ int u , v , w ; scanf("%lld%lld%lld" , &u , &v , &w); add(u , v , w); add(v , u , w); } spfa(s); int ans1 = -INF , ans2 = -INF; rep(i , 1 , n){ ans1 = max(ans1 , dis[i]); } spfa(n+1); rep(i , 1 , n){ ans2 = max(ans2 , dis[i]); } if(ans1 <= ans2*c){ cout << ans1 << endl; }else{ cout << ans2 << endl; } } signed main() { int t ; scanf("%lld" , &t); while(t--) solve(); }
解法3:朴素dijistra,建图使消防队之间联通且边权为0
//#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <algorithm> #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdio.h> #include <queue> #include <stack>; #include <map> #include <set> #include <string.h> #include <vector> #define ME(x , y) memset(x , y , sizeof(x)) #define SF(n) scanf("%d" , &n) #define rep(i , n) for(int i = 0 ; i < n ; i ++) #define INF 0x3f3f3f3f #define mod 998244353 #define PI acos(-1) using namespace std; typedef long long ll ; int ma[1020][1020]; int v , e , s , k , c ; int dis[1020]; int vis[1020]; int a[1020]; void Dijia(ll r) { for(int i = 1 ; i <= v ; i++) { vis[i] = 0 ; dis[i] = ma[r][i]; } vis[r] = 1 ; for(int i = 1 ; i < v ; i++) { int min1 = INF; int pos ; for(int j = 1 ; j <= v ; j++) { if(!vis[j] && min1 > dis[j]) { min1 = dis[j]; pos = j ; } } vis[pos] = 1 ; for(int j = 1 ; j <= v ; j++) { dis[j] = min(dis[j] , dis[pos] + ma[pos][j]); } } } int main() { int t ; scanf("%d" , &t); while(t--) { int u , vv , w ; int h = - INF , cc = -INF; scanf("%d%d%d%d%d" , &v , &e , &s ,&k , &c); for(int i = 1 ; i <= v ; i++) { for(int j = 1 ; j <= v ; j++) { if(i == j) ma[i][j] = 0 ; else ma[i][j] = INF ; } } for(int i = 0 ; i < k ; i++) { scanf("%d" , &a[i]); } for(int i = 0 ; i < e ; i++) { scanf("%d%d%d" , &u , &vv , &w); ma[u][vv] = ma[vv][u] = min(ma[u][vv] , w); } Dijia(s); for(int i = 1 ; i <= v ; i++) { h = max(h , dis[i]); } for(int i = 0 ; i < k ; i++) { for(int j = i + 1 ; j < k ; j++) { ma[a[i]][a[j]] = ma[a[j]][a[i]] = 0 ; } } Dijia(a[0]); for(int i = 1 ; i <= v ; i++) { cc = max(cc , dis[i]); } if(h <= cc * c) { printf("%d\n" , h); } else printf("%d\n" , cc); } return 0 ; }
解法4:第二种方法是增加一个点,将与每一个救援对之间的距离赋值为0。该点位源点;
//#include <bits/stdc++.h> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <algorithm> #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdio.h> #include <queue> #include <stack> #include <map> #include <set> #include <string.h> #include <vector> #define ME(x , y) memset(x , y , sizeof(x)) #define SF(n) scanf("%d" , &n) #define rep(i , n) for(int i = 0 ; i < n ; i ++) #define INF 0x3f3f3f3f #define mod 998244353 #define PI acos(-1) using namespace std; typedef long long ll ; ll v , e , s , k , c ; ll ma[1020][1020]; ll vis[1020]; ll dis[1020]; void Dijia(ll r) { for(int i = 1 ; i <= v ; i++) { vis[i] = 0 ; dis[i] = ma[r][i] ; } vis[r] = 1 ; for(int i = 1 ; i < v ; i++) { ll min1 = INF ; ll pos ; for(int j = 1 ; j <= v ; j++) { if(!vis[j] && min1 > dis[j]) { min1 = dis[j]; pos = j ; } } vis[pos] = 1 ; for(int j = 1 ; j <= v ; j++) { dis[j] = min(dis[j] , dis[pos] + ma[pos][j]); } } } int main() { int t ; scanf("%d" , &t); while(t--) { ll h = -INF , cc = -INF ; scanf("%lld%lld%lld%lld%lld" , &v , &e , &s , &k , &c); ll tea ; for(int i = 1 ; i <= v+1 ; i++) { for(int j = 1 ; j <= v+1 ; j++) { if(i == j) ma[i][j] = 0 ; else ma[i][j] = INF; } } for(int i = 0 ; i < k ; i++) { scanf("%lld" , &tea); ma[v+1][tea] = ma[tea][v+1] = 0 ; } for(int i = 0 ; i < e ; i++) { ll f , to , w ; scanf("%lld%lld%lld" , &f , &to , &w); ma[f][to] = ma[to][f] = min(ma[f][to] , w); } Dijia(s); for(int i = 1 ; i <= v ; i++) { h = max(dis[i] , h); } Dijia(v+1); for(int i = 1 ; i <= v ; i++) { cc = max(dis[i] , cc); } if(h <= cc * c) { printf("%lld\n" , h); } else { printf("%lld\n" , cc); } } return 0 ; }