1509: [NOI2003]逃学的小孩

题目链接

题目大意:从一棵树中找出三个点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; 
}

你可能感兴趣的:(1501-1750)