您的位置:首页 > 其它

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

2017-05-24 09:40 357 查看
https://vjudge.net/problem/Gym-100676H

题意:

给出一个n个城市,城市之间有距离为w的边,现在要选一个中心城市,使得该城市到其余城市的最大距离最短。如果有一些城市是强连通的,那么他们可以使用传送门瞬间到达。

思路:
因为强连通时可以瞬移,因为是无向图,所以计算边双连通分量然后重新建图,这样,也就不存在环了。

接下来,计算一下树的直径,因为中心城市肯定选在树的直径上,这样才有可能使最大的边最短。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
using namespace std;

const int maxn=1e5+5;
const long long INF =1e15+5;
typedef pair<long long,long long> pll;

struct Edge
{
long long u,v,c;
}edge[maxn<<2];

int n,m;
int pre[maxn],isbridge[maxn<<4],bcc_cnt,dfs_clock;
long long d[maxn][2];
vector<int> G[maxn];
vector<pll> tree[maxn];

int tarjan(int u,int fa)
{
int lowu=pre[u]=++dfs_clock;
for(int i=0;i<G[u].size();i++)
{
int temp=G[u][i];
int v=edge[temp].v;
if(!pre[v])
{
int lowv=tarjan(v,u);
lowu=min(lowu,lowv);
if(lowv>pre[u])
{
isbridge[temp]=isbridge[temp^1]=1;
}
}
else if(v!=fa)
lowu=min(lowu,pre[v]);
}
return lowu;
}

void dfs(int u)
{
pre[u]=bcc_cnt;
for(int i=0;i<G[u].size();i++)
{
int temp=G[u][i];
if(isbridge[temp])   continue;
int v=edge[temp].v;
if(!pre[v])  dfs(v);
}
}

void find_ebbc()
{
bcc_cnt=dfs_clock=0;
memset(pre,0,sizeof(pre));
memset(isbridge,0,sizeof(isbridge));

for(int i=1;i<=n;i++)
if(!pre[i])   tarjan(i,-1);

memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++)             //计算边—双连通分量
if(!pre[i])
{
bcc_cnt++;
dfs(i);
}
}

void rebuild()
{
for(int i=1;i<=bcc_cnt;i++)  tree[i].clear();
int tot=m<<1|1;
for(int i=3;i<=tot;i+=2)
{
if(isbridge[i])
{
int u=edge[i].v, v=edge[i].u;
tree[pre[u]].push_back(make_pair(pre[v],edge[i].c));
tree[pre[v]].push_back(make_pair(pre[u],edge[i].c));
}
}
}

int bfs(int u,int flag)
{
for(int i=1;i<=bcc_cnt;i++)  d[i][flag]=-1;
queue<int> Q;
Q.push(u);
d[u][flag]=0;
long long max_d=0;
int max_u=u;
while(!Q.empty())
{
u=Q.front(); Q.pop();
if(d[u][flag]>max_d)  {max_d=d[u][flag];max_u=u;}
for(int i=0;i<tree[u].size();i++)
{
int v=tree[u][i].first;
if(d[v][flag]==-1)
{
Q.push(v);
d[v][flag]=d[u][flag]+tree[u][i].second;
}
}
}
return max_u;
}

int main()
{
//freopen("D:\\input.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)  G[i].clear();
for(int i=1;i<=m;i++)
{
int u,v; long long w;
scanf("%d%d%lld",&u,&v,&w);
edge[i<<1|1].u=u; edge[i<<1|1].v=v; edge[i<<1|1].c=w;
edge[i<<1].u=v; edge[i<<1].v=u; edge[i<<1].c=w;
G[u].push_back(i<<1|1);
G[v].push_back(i<<1);
}
find_ebbc();
rebuild();

int p=bfs(1,0);
int q=bfs(p,0);   //计算出与一端点p的距离
long long length=d[q][0];
int z=bfs(q,1);

long long ans=INF;
long long inx=n+1;
for(int i=1;i<=n;i++)
{
int cnt=pre[i];
if(d[cnt][0]+d[cnt][1]!=length)  continue;
long long num=max(d[cnt][0],d[cnt][1]);
if(ans>num)
{
ans=num;
inx=i;
}
}
printf("%lld %lld\n",inx,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: