2017 湘潭大学邀请赛/江苏省省赛 H题 Highway

题目链接

ACM职业生涯难忘的一道题,现场赛三个人一起卡了三个小时的题。

当时此题现场赛过的人很多,我队三人根据时限判断估计不是一个能取巧推公式的题,当时S10和YaoJinhui主要在纸上模拟找规律,而我其实一开始就很确信最终答案的每条路径都跟叶子节点有关,但对每一个度为1的节点进行搜索极端条件下一定超时,所以一直想优化搜索的策略。

后来离结束还有1h时,由我上机对每个叶子节点暴力搜索一发,但因为只贪心选择了最长的路,而并没有考虑是否形成了一个圈,所以一直没过样例,所以到比赛最后也没有过掉此题。

后来了解到了直径的概念,才知道此题其实甚水,只需要考虑每个节点到直径两点的最大距离,然后累加即可。所以其实比赛时的思路是没错的,只是不需要对所有叶子节点都进行搜索,只需要搜索两个直径端点。

设直径两个端点分别是 rt_1 和 rt_2
代码的思路是先从1节点搜索到距离最远的直径上的节点rt_1,然后再从rt_1搜索找到距其最远的节点rt_2,同时更新每一个点到rt_1的距离,再从rt_2进行搜索更新每一个点到直径节点的距离,然后每个点到直径节点的最大距离进行累加。因直径考虑了两次,故减去一次直径就是最后的答案,三次搜索即可。

1400ms。

代码:

#include
using namespace std;
typedef __int64 ll;

const int A = 1e5 + 100;
class P{
public:
    int v,next;
    ll w;
}G[A*10];
ll Dis[A],Max;
int head[A];
bool vis[A];
int n,tot,rt_1,rt_2;

void add(int u,int v,ll w){
    G[tot].v = v;
    G[tot].w = w;
    G[tot].next = head[u];
    head[u] = tot++;
}

void dfs(int u,ll dis){
    vis[u] = 1;
    if(dis > Max){
        Max = dis;
        rt_1 = u;
    }
    for(int i=head[u] ;i!=-1;i=G[i].next){
        int v = G[i].v;
        ll w = G[i].w;
        if(vis[v] == 0){
            dfs(v,dis+w);
        }
    }
}

void Dfs(int u,ll dis,bool type){
    vis[u] = 1;
    Dis[u] = max(Dis[u],dis);
    if(type && dis > Max){
        rt_2 = u;
        Max = dis;
    }

    for(int i=head[u] ;i!=-1 ;i=G[i].next){
        int v = G[i].v;
        ll w = G[i].w;

        if(vis[v] == 0){
            Dfs(v,dis+w,type);
        }
    }
}

void solve(){
    rt_1 = rt_2 = 0;
    memset(vis,0,sizeof(vis));
    Max = 0;
    dfs(1,0);
    //printf("%I64d rt=%d\n",Max,rt_1);
    memset(Dis,0,sizeof(Dis));
    memset(vis,0,sizeof(vis));
    Max = 0;
    Dfs(rt_1,0,1);
    //printf("%I64d %I64d rt_1=%d rt_2=%d\n",Dis[rt_1],Dis[rt_2],rt_1,rt_2);

    memset(vis,0,sizeof(vis));
    Dfs(rt_2,0,0);
    //printf("%I64d %I64d rt_1=%d rt_2=%d\n",Dis[rt_1],Dis[rt_2],rt_1,rt_2);
    Dis[rt_1] = 0;
    ll ans = 0;
    for(int i=1 ;i<=n ;i++){
        ans += Dis[i];
    }
    printf("%I64d\n",ans);
}

int main(){
    //freopen("input","r",stdin);
    while(~scanf("%d",&n)){
        memset(head,-1,sizeof(head));
        tot = 0;
        for(int i=1 ;i

你可能感兴趣的:(2017 湘潭大学邀请赛/江苏省省赛 H题 Highway)