样例没过却A了,求教(n*n的时间复杂度,有注释)玄关
查看原帖
样例没过却A了,求教(n*n的时间复杂度,有注释)玄关
1212465
SilVeR__WolF楼主2024/7/18 14:10
#include<bits/stdc++.h>
using namespace std;
#define M 5005
int n,mxlen,trp,pl,pr,value,ans=2e9,pre[M],d[M],dl[M],dr[M],dn[M];
/*
mxlen 每次dfs的最大路径值;trp 每次dfs的起始节点;pl 直径左端点;pr 直径右端点 
value 每次删掉的路径费用;ans 答案 ;pre 直径路径上每个点的父亲;d 每次dfs 每个点到根的距离
dl/dr 每个点到左/右直径端点的距离;dn 每个点的最大链长 
*/ 
vector <int> w[M];//所有路径 
vector <int> v[M];//所有路径费用 
bool c[M][M];
//c[x][y]为1表示x到y的路径处于断开状态 
void dfs(int x,int fa,int cnt,int jl)//cnt表示处于第几次dfs jl表示是否需要记录路径 
{
	if(cnt==2&&jl==1)	pre[x]=fa;
	for(int i=0;i<w[x].size();i++){
		int y=w[x][i],k=v[x][i];
		if(y==fa||c[x][y])	continue;
		d[y]=d[x]+k;
		if(cnt==2)	dl[y]=d[y];
		if(cnt==3){
			dr[y]=d[y];
			dn[y]=max(dl[y],dr[y]);//记录每个点的最大链长 
			if(mxlen>dn[y])	mxlen=dn[y];//记录最大链长中的最小值,即中心的最大链长 
		}
		if(mxlen<d[y]&&cnt!=3)	mxlen=d[y],trp=y;
		dfs(y,x,cnt,jl);
	}
}
void get(int x,int jl)//获取直径 
{
	trp=x;
	for(int i=1;i<=2;i++){
		mxlen=0;
		memset(d,0,sizeof d);
		dfs(trp,0,i,jl);
		if(i==1)	pl=trp;
		else		pr=trp;//记录左右端点 
	}
}
int getzx(int x)//获取中心 
{
	get(x,0);
	int zj=mxlen,mxlen=2e9;//zj是直径长 
	memset(d,0,sizeof d);
	dfs(pr,0,3,0);//将每个点到右端点的距离存入dr数组,并找出中心的最大链长(mxlen) 
	return zj;
}
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y,z; cin>>x>>y>>z;
		w[x].push_back(y); w[y].push_back(x);
		v[x].push_back(z); v[y].push_back(z);
	}
	get(1,1);
	for(int i=pr;i;i=pre[i]){//枚举直径上的点并断开 
		int x=i,y=pre[x];
		if(!x||!y)	continue;
		c[x][y]=c[y][x]=true;
		for(int j=0;j<w[x].size();j++){
			if(w[x][j]==y){//找出断开路径的费用 
				value=v[x][j];
				break;
			}
		}
		int zj1=getzx(x),t1=mxlen;//记录以x为根节点的直径和中心的最大链长 
		int zj2=getzx(y),t2=mxlen;//记录以y为根节点的直径和中心的最大链长 
		int res=max(max(zj1,zj2),t1+t2+value);//找出当前接上一条边的最小直径 
		ans=min(ans,res);
		c[x][y]=c[y][x]=false;//回复道路 
//		cout<<x<<" "<<y<<" "<<t1<<" "<<t2<<"\n";
	}
	cout<<ans;
	return 0;
}
2024/7/18 14:10
加载中...