poj1985 Cow Marathon (el diámetro del árbol)

Maratón de vacas

Límite de tiempo:  2000MS   Límite de memoria:  30000 K
Envíos totales: 9653   Aceptado:  4411
Límite de tiempo del caso:  1000MS

Descripción

Después de enterarse de la epidemia de obesidad en los EE. UU., El granjero John quiere que sus vacas hagan más ejercicio, por lo que se ha comprometido a crear un maratón bovino para que corran sus vacas. La ruta del maratón incluirá un par de granjas y un camino compuesto por una secuencia de caminos entre ellos. Como FJ quiere que las vacas hagan todo el ejercicio posible, quiere encontrar las dos granjas en su mapa que están más alejadas entre sí (la distancia se mide en términos de la longitud total del camino en el camino entre las dos granjas). Ayúdalo a determinar las distancias entre este par de granjas más lejanas. 

Aporte

* Líneas 1 .....: Mismo formato de entrada que "Navigation Nightmare".

Producción

* Línea 1: un número entero que indica la distancia entre el par de fincas más lejano. 

Entrada de muestra

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S

Salida de muestra

52

Pista

El maratón más largo se ejecuta desde la granja 2 por las carreteras 4, 1, 6 y 3 hasta la granja 5 y tiene una longitud de 20 + 3 + 13 + 9 + 7 = 52. 

Fuente

USACO 2004 Febrero

Significado de la pregunta: encuentre el diámetro del árbol, pregunta de plantilla

Hay dos formas de encontrar el diámetro del árbol.

(1) Explicación del método de dp de árbol : https://saoka.blog.luogu.org/shu-di-zhi-jing

Definición de matriz:

dp [x]: la distancia desde el nodo más alejado de xa x en el subárbol enraizado en x

f [x]: la longitud de la más larga de todas las cadenas que pasan por el punto x

edge (u, v): la longitud de la ruta desde el nodo u hasta el nodo v

Ideas:

  • Comience desde los nodos hoja y combínelos hacia arriba para encontrar d [x] para cada nodo x. La operación específica puede ser enumerando cada borde de x, y luego transferir a través de la ecuación de transición:

    dp [x] = max (dp [v_i] + borde (x, v_i), dp [x])

  • Luego, considere cómo hallar f [x]. Si V1 y V2 son respectivamente los nodos más lejanos y segundo distantes que se puede llegar desde el nodo x, entonces podemos conseguir fácilmente que la cadena más larga a través de x se determina por (x, v1) y (x, v2) consiste en. Entonces, cuando buscamos d [x], si encontramos un punto que puede actualizar d [x], entonces sumamos estos dos valores d [] juntos, de modo que podamos asegurarnos de que podemos obtener el punto más lejano y el segundo punto más lejano. punto.

//树形dp
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int head[N], tot, ans;
int dp[N]; //以x为根的子树中,与x最远的节点到x的距离
bool vis[N];

struct Edge {
    int to, w, next;
} edge[M];

void init() {
    tot = 0;
    memset(head, -1, sizeof(head));
}

void addedge(int u, int v, int w) {
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void dfs(int u) {
    vis[u] = 1;
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to;
        if(vis[v]) continue;
        dfs(v);
        //设v1、v2分别为从节点x出发能走到的最远、次远节点,那么经过x的最长链是由(x,v1)和(x,v2)组成的
        //在求d[x]的时候,如果找到了一个点能够更新d[x], 那么就把这两个d[]值相加,这样一定可以保证能够取到最远点和次远点
        ans = max(ans, dp[u] + dp[v] + edge[i].w);
        dp[u] = max(dp[u], dp[v] + edge[i].w);
    }
}

int main() {
    char c;
    int n, m, u, v, w;
    init();
    scanf("%d%d", &n, &m);
    while(m--) {
        scanf("%d%d%d", &u, &v, &w);
        cin >> c;
        addedge(u, v, w);
        addedge(v, u, w);
    }
    for(int i = 1; i <= n; ++i) vis[i] = 0;
    for(int i = 1; i <= n; ++i) dp[i] = 0;
    dfs(1);
    printf("%d\n", ans);
    return 0;
}

(2) Dos veces dfs buscando explicación: https://www.cnblogs.com/handsome-zyc/p/11237529.html

Método: comience desde cualquier punto P, encuentre el punto más alejado Q de él, luego comience desde el punto Q, encuentre el punto más alejado W de él, la distancia de W a Q es el diámetro de

La prueba es como sigue:

① Si P ya está en el diámetro, según la definición del diámetro del árbol, sabemos que Q también está en el diámetro y es un punto final del diámetro.

②Si P no está en el diámetro, usamos el método de contradicción, asumiendo que WQ no es el diámetro en este momento y AB es el diámetro

---> Si AB y PQ tienen un punto de intersección C, ya que P es el más alejado de Q, entonces PC + CQ> PC + CA, entonces CQ> CA, es fácil obtener CQ + CB> CA + CB, es decir , CQ + CB> AB, es contradictorio con el diámetro de AB, lo cual no es cierto, como se muestra en la siguiente figura (donde AB y PQ no son necesariamente líneas rectas, se dibujan por conveniencia):

---> Si no hay intersección entre AB y PQ, M es cualquier punto de AB y N es cualquier punto de PQ. En primer lugar, sigue siendo NP + NQ> NQ + MN + MB, mientras que restando NQ, obtenemos NP> MN + MB. Es fácil saber que NP + MN> MB, entonces NP + MN + MA> MB + MAMÁ,

Es decir, NP + MN + MA> AB, y AB es una contradicción de diámetro, por lo que esta situación no es cierta, como se muestra en la siguiente figura:

 

//两次dfs
//先从任意一点P出发,找离它最远的点Q,再从点Q出发,找离它最远的点W,W到Q的距离就是是的直径
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int head[N], tot, dis[N], ans, id;

struct Edge {
    int to, w, next;
} edge[M];

void init() {
    tot = 0;
    memset(head, -1, sizeof(head));
}

void addedge(int u, int v, int w) {
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void dfs(int u, int fa) {
    if(ans < dis[u]) {
        ans = dis[u];
        id = u;
    }
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to;
        if(v == fa) continue;
        dis[v] = dis[u] + edge[i].w;
        dfs(v, u);
    }
}

int main() {
    char c;
    int n, m, u, v, w;
    init();
    scanf("%d%d", &n, &m);
    while(m--) {
        scanf("%d%d%d", &u, &v, &w);
        cin >> c;
        addedge(u, v, w);
        addedge(v, u, w);
    }
    for(int i = 1; i <= n; ++i) dis[i] = 0;
    ans = 0;
    dfs(1, 0);
    ans = 0, dis[id] = 0;
    dfs(id, 0);
    printf("%d\n", ans);
    return 0;
}

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43871207/article/details/110562719
Recomendado
Clasificación