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 " , h); } else printf("%d " , 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 " , h); } else { printf("%lld " , cc); } } return 0 ; }