题意:
给出一个n个城市,城市之间有距离为w的边,现在要选一个中心城市,使得该城市到其余城市的最大距离最短。如果有一些城市是强连通的,那么他们可以使用传送门瞬间到达。
思路:
因为强连通时可以瞬移,因为是无向图,所以计算边双连通分量然后重新建图,这样,也就不存在环了。
接下来,计算一下树的直径,因为中心城市肯定选在树的直径上,这样才有可能使最大的边最短。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 using namespace std; 11 12 const int maxn=1e5+5; 13 const long long INF =1e15+5; 14 typedef pair<long long,long long> pll; 15 16 struct Edge 17 { 18 long long u,v,c; 19 }edge[maxn<<2]; 20 21 int n,m; 22 int pre[maxn],isbridge[maxn<<4],bcc_cnt,dfs_clock; 23 long long d[maxn][2]; 24 vector<int> G[maxn]; 25 vector<pll> tree[maxn]; 26 27 int tarjan(int u,int fa) 28 { 29 int lowu=pre[u]=++dfs_clock; 30 for(int i=0;i<G[u].size();i++) 31 { 32 int temp=G[u][i]; 33 int v=edge[temp].v; 34 if(!pre[v]) 35 { 36 int lowv=tarjan(v,u); 37 lowu=min(lowu,lowv); 38 if(lowv>pre[u]) 39 { 40 isbridge[temp]=isbridge[temp^1]=1; 41 } 42 } 43 else if(v!=fa) 44 lowu=min(lowu,pre[v]); 45 } 46 return lowu; 47 } 48 49 void dfs(int u) 50 { 51 pre[u]=bcc_cnt; 52 for(int i=0;i<G[u].size();i++) 53 { 54 int temp=G[u][i]; 55 if(isbridge[temp]) continue; 56 int v=edge[temp].v; 57 if(!pre[v]) dfs(v); 58 } 59 } 60 61 void find_ebbc() 62 { 63 bcc_cnt=dfs_clock=0; 64 memset(pre,0,sizeof(pre)); 65 memset(isbridge,0,sizeof(isbridge)); 66 67 for(int i=1;i<=n;i++) 68 if(!pre[i]) tarjan(i,-1); 69 70 memset(pre,0,sizeof(pre)); 71 for(int i=1;i<=n;i++) //计算边—双连通分量 72 if(!pre[i]) 73 { 74 bcc_cnt++; 75 dfs(i); 76 } 77 } 78 79 void rebuild() 80 { 81 for(int i=1;i<=bcc_cnt;i++) tree[i].clear(); 82 int tot=m<<1|1; 83 for(int i=3;i<=tot;i+=2) 84 { 85 if(isbridge[i]) 86 { 87 int u=edge[i].v, v=edge[i].u; 88 tree[pre[u]].push_back(make_pair(pre[v],edge[i].c)); 89 tree[pre[v]].push_back(make_pair(pre[u],edge[i].c)); 90 } 91 } 92 } 93 94 int bfs(int u,int flag) 95 { 96 for(int i=1;i<=bcc_cnt;i++) d[i][flag]=-1; 97 queue<int> Q; 98 Q.push(u); 99 d[u][flag]=0; 100 long long max_d=0; 101 int max_u=u; 102 while(!Q.empty()) 103 { 104 u=Q.front(); Q.pop(); 105 if(d[u][flag]>max_d) {max_d=d[u][flag];max_u=u;} 106 for(int i=0;i<tree[u].size();i++) 107 { 108 int v=tree[u][i].first; 109 if(d[v][flag]==-1) 110 { 111 Q.push(v); 112 d[v][flag]=d[u][flag]+tree[u][i].second; 113 } 114 } 115 } 116 return max_u; 117 } 118 119 120 int main() 121 { 122 //freopen("D:\\input.txt","r",stdin); 123 int T; 124 scanf("%d",&T); 125 while(T--) 126 { 127 scanf("%d%d",&n,&m); 128 for(int i=1;i<=n;i++) G[i].clear(); 129 for(int i=1;i<=m;i++) 130 { 131 int u,v; long long w; 132 scanf("%d%d%lld",&u,&v,&w); 133 edge[i<<1|1].u=u; edge[i<<1|1].v=v; edge[i<<1|1].c=w; 134 edge[i<<1].u=v; edge[i<<1].v=u; edge[i<<1].c=w; 135 G[u].push_back(i<<1|1); 136 G[v].push_back(i<<1); 137 } 138 find_ebbc(); 139 rebuild(); 140 141 int p=bfs(1,0); 142 int q=bfs(p,0); //计算出与一端点p的距离 143 long long length=d[q][0]; 144 int z=bfs(q,1); 145 146 long long ans=INF; 147 long long inx=n+1; 148 for(int i=1;i<=n;i++) 149 { 150 int cnt=pre[i]; 151 if(d[cnt][0]+d[cnt][1]!=length) continue; 152 long long num=max(d[cnt][0],d[cnt][1]); 153 if(ans>num) 154 { 155 ans=num; 156 inx=i; 157 } 158 } 159 printf("%lld %lld\n",inx,ans); 160 } 161 return 0; 162 }