题目链接
题目大意:从一棵树中找出三个点x,y,z,使min(dis[x][z],dis[y][z])+dis[x][y]最大
题解:有比较神的O(n)dp做法,但我比较弱,这里写一下贪心做法。如果只考虑让dis[x][y]最大,取直径最优,另一个点直接枚举。本题这样就能过了……可以画个图感性认知一下。证明详见此处
我的收获:忽视一部分直接贪心……
#include
#include
#include
#include
using namespace std;
#define M 200010
int st,ed;
int n,m,t;
int head[M];
long long tia,dis[M],dis2[M];
struct edge{int to,val,nex;}e[M*3];
void add(int u,int v,int w){e[t]=edge{v,w,head[u]};head[u]=t++;}
void dfs(int x,int fa)
{
for(int i=head[x];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v!=fa) dis[v]=dis[x]+e[i].val,dfs(v,x);
}
if(dis[x]>dis[st]) st=x;//找一个起点
}
void dfs2(int x,int fa)
{
for(int i=head[x];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v!=fa) dis[v]=dis[x]+e[i].val,dfs2(v,x);
}
if(dis[x]>tia) ed=x,tia=dis[x];
}
void work()
{
dfs(1,0);memset(dis,0,sizeof(dis));
dfs2(st,0);memcpy(dis2,dis,sizeof(dis));//dis2表示st到其他点距离
memset(dis,0,sizeof(dis));dfs(ed,0);//dis表示ed到其他点距离
long long ret=0;
for(int i=1;i<=n;i++)
ret=max(ret,min(dis[i],dis2[i]));
printf("%lld\n",ret+tia);
}
void init()
{
int x,y,z;t=0;
memset(head,-1,sizeof(head));
cin>>n>>m;
while(m--) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
}
int main()
{
init();
work();
return 0;
}