VIJOS P1476 旅游规划(csapc)

来源:互联网 发布:丹尼格林知乎 编辑:程序博客网 时间:2024/05/09 20:59

描述

W市的交通规划出现了重大问题,市政府下决心在全市的各大交通路口安排交通疏导员来疏导密集的车流。但由于人员不足,W市市长决定只在最需要安排人员的路口安放人员。具体说来,W市的交通网络十分简单,它包括n个交叉路口和n-1条街道,任意一条街道连接两个交叉路口,并且任意两个交叉路口之间都存在一条路径互相连接。经过长期调查结果显示如果一个交叉路口位于W市交通网的最长路径上,那么这个路口必然拥挤不堪,所谓最长路径定义为某条路径p=(v1,v2,v3…vk),路径经过的路口各不相同且城市中不存在长度>k的路径(因此可能存在着不唯一的最长路径)。因此W市市长希望知道有哪些路口位于城市交通网的最长路径之上。

格式

输入格式

第一行包括一个整数n。

之后的n-1行每行包括两个整数u, v表示编号为u和v的路口之间存在着一条街道(注意:路口被依次编号为0到n-1)

输出格式

输出包括若干行,每行包括一个整数——某个位于最长路上路口的编号。

为了确保解唯一,我们规定位于所有最长路上的路口按编号顺序从小到大输出。

样例1

样例输入1[复制]

100 10 20 40 60 71 32 54 86 9

样例输出1[复制]

012345689

提示

这里存在着若干条最长路径,其中的两条是3-1-0-2-5与8-4-0-6-9,他们的长度都是5,但是不存在长度>5的路径且所有最长路径都不包括路口7,所以答案中没有7。

数据范围:
对于50%的数据保证n<=1000
对于100%的数据保证n<=200000


题意: 有一棵树, 输出, 在最长路的节点。 

思路: 树形DP

因为点是20W, 用push_back 都超时, 换了静态链表。 SPFA的模版

先往下DP, 求出子节点的第一长,和第二长的路径。

然后往上DP, 其实也是也是往下DP, 只不过是, 根节点给儿子节一个最大长路径,  再次更新最长, 和次长路径。

然后对每个节点求出最长路, max = fir  + sec;

然后对满足  fir + sec == max 的就是要求的节点

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;//树形DPconst int V = 200000 + 50;const int inf = 0x7fffffff;int n, Max;int pnt[V * 2], nxt[V * 2], head[V * 2], e;//建图int Fir[V][2], Sec[V][2];bool vis[V]; //标记搜索inline void addedge(int u, int v) {    pnt[e] = v;    nxt[e] = head[u];    head[u] = e++;}void update(int index, int len, int id) {    if(len > Fir[index][0]) {        Sec[index][0] = Fir[index][0];        Sec[index][1] = Fir[index][1];        Fir[index][0] = len;        Fir[index][1] = id;    }    else if(len > Sec[index][0]) {        Sec[index][0] = len;        Sec[index][1] = id;    }}int down_dp(int u) {    vis[u] = true;    for(int i = head[u]; i != -1; i = nxt[i])        if(!vis[pnt[i]])            update(u, down_dp(pnt[i]) + 1, pnt[i]);    return Fir[u][0];}void up_dp(int u, int fa, int len) {    update(u, len, fa);    Max = max(Max, Fir[u][0] + Sec[u][0]);    vis[u] = true;    for(int i = head[u]; i != -1; i = nxt[i]) {        if(vis[pnt[i]])            continue;        if(pnt[i] != Fir[u][1])            up_dp(pnt[i], u, 1 + Fir[u][0]);        else            up_dp(pnt[i], u, 1 + Sec[u][0]);    }}int main() {    int i, j, k;    scanf("%d", &n);    //建图    memset(head, -1, sizeof(head));    for(i = 0; i < n - 1; ++i) {        int a, b;        scanf("%d%d", &a, &b);        addedge(a, b);        addedge(b, a);    }    down_dp(0); //求节点到各儿子路径的最长路    memset(vis, false, sizeof(vis));    up_dp(0, n, 0); //求节点到父亲路径的最长路    for(i = 0; i < n; ++i)        if(Fir[i][0] + Sec[i][0] == Max)            printf("%d\n", i);}


原创粉丝点击