Gym - 100676H H. Capital City (边双连通分量缩点+树的直径)

https://vjudge.net/problem/Gym-100676H

题意:

给出一个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 }

 

posted @ 2017-05-24 09:40  Kayden_Cheung  阅读(259)  评论(0编辑  收藏  举报
//目录