uvalive 5026 树-直径


这个问题挺有趣,所以锲而不舍想要知道怎么做

了解之后发现也挺直观和朴素,怎么当时就想不出来呢。。

1.求最长路

2.要移动的边肯定在最长路上

3.枚举最长路上的每条边,对于每条边u->v(权值为w),移动它的策略是把u,v两个端点接在两边子树的最长路的中间位置

4.接好后的最长路不一定是 x+w+y,还有可能是两个子树的最长路,要判断下


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 3000
int max(int aa,int bb)
{return aa>bb?aa:bb;}
int min(int aa,int bb)
{return aa<bb?aa:bb;}
struct Edge
{
	int v,w;
	bool flag;
	Edge()
	{
		v=w=0;flag=true;
	}
}edge[N*2];
int head[N],adj[N*2],e,n;
int path[N],dist[N],D,end_v,end_u,temp[N];
void dfs(int u,int fa)
{
	if(D<dist[u])
		D=dist[u],end_v=u;
	for(int i=head[u];i!=-1;i=adj[i])
		if(edge[i].v!=fa&&edge[i].flag)
		{
			dist[edge[i].v]=dist[u]+edge[i].w;
			temp[edge[i].v]=i;
			dfs(edge[i].v,u);
		}
}

void find(int root,int pre_root)
{
	memset(dist,0,sizeof(dist));
	D=-1;
	dfs(root,pre_root);
	memset(dist,0,sizeof(dist));
	D=-1;end_u=end_v;
	dfs(end_u,-1);
}
int subtree_max_mid(int st,int ed,int *t,int DD)
{
	int ret=0x3fffffff;
	int u=ed,j;
	while(u!=st)
	{
		ret=min(ret,max(dist[u],DD-dist[u]));
		j=t[u];
		u=edge[j^1].v;
	}
	if(ret>=0x3fffffff) //没有进入while,没有子树
		return 0;
	return ret;
}

void insert(int u,int v,int w)
{
	edge[e].v=v;edge[e].w=w;
	adj[e]=head[u];head[u]=e++;
}
int main ()
{
	int test;scanf("%d",&test);
	for(int k=1;k<=test;++k)
	{
		memset(head,-1,sizeof(head));
		e=0;
		scanf("%d",&n);
		if(n==1)
		{
			printf("Case %d: 0\n",k);
			continue;
		}
		int u,v,w;
		for(int i=1;i<n;++i)
		{
			scanf("%d%d%d",&u,&v,&w);
			insert(u,v,w);
			insert(v,u,w);
		}
		find(1,-1);
		for(int i=0;i<=n;++i)
			path[i]=temp[i];
		int st,ed,j;
		st=end_u,ed=end_v;
		u=ed;
		int ans=0x3fffffff,res,x,y,d1,d2;
		while(u!=st)
		{
			j=path[u];
			edge[j^1].flag=edge[j].flag=false;
			find(u,edge[j^1].v);
			d1=D;
			x=subtree_max_mid(end_u,end_v,temp,D);
			find(edge[j^1].v,u);
			d2=D;
			y=subtree_max_mid(end_u,end_v,temp,D);
			res=max(d1,d2);
			ans=min(ans,max(res,x+edge[j].w+y));

			u=edge[j^1].v;
			edge[j^1].flag=edge[j].flag=true;
		}
		printf("Case %d: %d\n",k,ans);
	}
	//system("pause");
	return 0;
}


你可能感兴趣的:(uvalive 5026 树-直径)