NOI03 逃学的小孩

来源:互联网 发布:第四十一知乎 编辑:程序博客网 时间:2024/06/11 23:00

问题描述

Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?一听说要考试,Chris的父母就心急如焚,他们决定在尽量短的时间内找到Chris。他们告诉Chris的老师:根据以往的经验,Chris现在必然躲在朋友ShermieYashiro家里偷玩《拳皇》游戏。现在,我们就从家出发去找Chris,一但找到,我们立刻给您打电话。说完砰的一声把电话挂了。

Chris居住的城市由N个居住点和若干条连接居住点的双向街道组成,经过街道x需花费Tx分钟。可以保证,任两个居住点间有且仅有一条通路。Chris家在点CShermieYashiro分别住在点A和点BChris的老师和Chris的父母都有城市地图,但Chris的父母知道点ABC的具体位置而Chris的老师不知

为了尽快找到ChrisChris的父母会遵守以下两条规则:

l 如果A距离CB距离C近,那么Chris的父母先去Shermie家寻找Chris,如果找不到,Chris的父母再去Yashiro家;反之亦然

l Chris的父母总沿着两点间唯一的通路行走。

这题应该说是树形dp中难度较大的题了。具体参考陈瑜希的论文。

主要思想是通过两遍dfs。第一遍任意选取一个节点作为根,然后求得每个节点子树中前3远的距离。

第二遍dfs是对每个节点求其到其父亲节点引出来的其他节点的最远距离,重新调整每个节点的前3远的距离。

并且第二遍dfs有两个步骤,前一个步骤保证搜索的方向是层次的,这样就能够保证子树更新距离时,父亲节点已更新完毕。

然后为什么父亲节点会引出一条路径。其实是因为每个分叉结点的前3远节点在不同的三颗子树(以该节点为根),也就是三颗子树交于该点,而过该点从其父亲方向过来的只可能有一条,如果大于1条,则说明三颗子树交于多个点组成的线段。

然后可能有人会有疑问?如果仅有一条树链,那么三点不是不交于1点,但是因为我们枚举了所有分叉点,对于这条链上的中间那个点作为分叉点,并且按照论文中转换,也就是添加边权为0的节点,那么就符合题意了,这个在代码里赋初值时是有体现的。但可能有人又有疑问了,其他点作为分叉点,最优解不就不交于1点了。

没错,但是此时根据代码,这些点只会求得以三颗子树交于该点的最优解,因此这些点得不到最优解。但是因为枚举了所有点作为分叉点,所以必然会在以那个中间点作为分叉点时,得到最优解。

所以这些完全不需要担心。。。但是如果你有这些顾虑,那说明你思考问题相当严密,值得鼓励。


代码:

#include<cstdio>#include<iostream>#include<cstring>#include<vector>#include<algorithm>#define ll long long#define Maxn 200010using namespace std;struct edge{    int u,v;    ll val;}p[Maxn];struct maxx{    int ori;    ll dis;    bool operator<(const maxx &a)const{        return dis>a.dis;    }}ma[Maxn][4];vector<edge> dv[Maxn];ll ans;int vis[Maxn];void dfs1(int u){    vis[u]=1;    for(int i=0;i<dv[u].size();i++){        int v=u==dv[u][i].u?dv[u][i].v:dv[u][i].u;        if(!vis[v]&&u!=v){            dfs1(v);            ma[u][3].dis=ma[v][0].dis+dv[u][i].val;            ma[u][3].ori=v;            sort(ma[u],ma[u]+4);            ans=max(ans,ma[u][0].dis+2*ma[u][1].dis+ma[u][2].dis);        }    }}void dfs2(int u){    vis[u]=1;    for(int i=0;i<dv[u].size();i++){        int v=u==dv[u][i].u?dv[u][i].v:dv[u][i].u;        if(vis[v]&&u!=v){            if(ma[v][0].ori!=u)                ma[u][3].dis=ma[v][0].dis+dv[u][i].val;            else                ma[u][3].dis=ma[v][1].dis+dv[u][i].val;            sort(ma[u],ma[u]+4);            ans=max(ans,ma[u][0].dis+2*ma[u][1].dis+ma[u][2].dis);            break;        }    }    for(int i=0;i<dv[u].size();i++){        int v=u==dv[u][i].u?dv[u][i].v:dv[u][i].u;        if(!vis[v]&&u!=v) dfs2(v);    }}int main(){    int n,m,val;    scanf("%d%d",&n,&m);    ans=0;    for(int i=1;i<=n;i++) dv[i].clear();    for(int i=0;i<m;i++){        scanf("%d%d%lld",&p[i].u,&p[i].v,&p[i].val);        dv[p[i].u].push_back(p[i]);        dv[p[i].v].push_back(p[i]);    }    memset(vis,0,sizeof vis);    memset(ma,0,sizeof ma);    dfs1(1);    memset(vis,0,sizeof vis);    dfs2(1);    printf("%lld\n",ans);return 0;}


0 0
原创粉丝点击