gym102391I Minimum Diameter Spanning Tree 带权最小直径生成树

https://codeforces.com/gym/102391/problem/I

学习自https://blog.csdn.net/crazy_ac/article/details/8816877

板题做了一个下午,头快想烂了

首先找到图的绝对中心,然后由于边权不为1,所以把所有边权都*2,然后中心到其他点的距离也会是整数了,确定中心后就从u,v开始跑,记得dis[u],dis[v]要设为真正的初始值。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=510;
const ll inf=1ll<<61;

int n,m,s1,s2,tot;ll ans;
int frm[maxl],ansx[maxl],ansy[maxl];
ll dis[maxl];
ll d[maxl][maxl],w[maxl][maxl],rk[maxl][maxl];
typedef pair<ll,int> p;
priority_queue<p,vector<p>,greater<p> >q;
vector<int> e[maxl];
bool vis[maxl];

inline void prework()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			w[i][j]=d[i][j]=inf;
	for(int i=1;i<=n;i++)
		w[i][i]=d[i][i]=0;
	int u,v,l;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&l);l*=2;
		d[u][v]=d[v][u]=w[u][v]=w[v][u]=l;
		e[u].push_back(v);e[v].push_back(u);
	}
}

inline ll findct()
{
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
			rk[i][j]=j;
		for(int j=1;j<=n;j++)
			for(int k=j+1;k<=n;k++)
			if(d[i][rk[i][j]]>d[i][rk[i][k]])
				swap(rk[i][j],rk[i][k]);
	}
	ll mi=inf;
	for(int u=1;u<=n;u++)
		for(int v:e[u])
		{
			if(u>v)
				continue;
			if((d[u][rk[u][n]]*2)<mi)
			{
				dis[s1]=dis[s2]=inf;
				mi=d[u][rk[u][n]]*2,s1=s2=u,dis[u]=0;
			}
			if((d[v][rk[v][n]]*2)<mi)
			{
				dis[s1]=dis[s2]=inf;
				mi=d[v][rk[v][n]]*2,s1=s2=v,dis[v]=0;
			}
			for(int last=n,i=n-1;i;i--)
			if(d[v][rk[u][i]]>d[v][rk[u][last]])
			{
				ll tmp=d[u][rk[u][i]]+d[v][rk[u][last]]+w[u][v];
				if(tmp<mi)
				{	
					dis[s1]=dis[s2]=inf;
					mi=tmp;s1=u,s2=v;
					dis[s1]=tmp/2-d[u][rk[u][i]];
					dis[s2]=w[u][v]-dis[s1];
				}
				last=i;
			}
		}
	return mi/2;
}

inline void mainwork()
{
	for(int i=1;i<=n;i++)
		dis[i]=inf,vis[i]=false;
	ans=findct();
	if(s1!=s2)
		q.push({dis[s1],s1}),q.push({dis[s2],s2});
	else
		q.push({dis[s1],s1});
	tot=0;
	if(s1!=s2)
		++tot,ansx[1]=s1,ansy[1]=s2;
	int u;p d;
	while(q.size())
	{
		d=q.top();q.pop();
		u=d.second;
		if(d.first!=dis[u] || vis[u])
			continue;
		vis[u]=true;
		if(u!=s1 && u!=s2)
			++tot,ansx[tot]=frm[u],ansy[tot]=u;
		for(int v:e[u])
		{
			if(dis[v]<=dis[u]+w[u][v])
				continue;
			dis[v]=dis[u]+w[u][v];frm[v]=u;
			q.push({dis[v],v});
		}
	}
}

inline void print()
{
	printf("%lld\n",ans);
	for(int i=1;i<=n-1;i++)
		printf("%d %d\n",ansx[i],ansy[i]);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/109040994