树形dp题集之树的直径

来源:互联网 发布:好的外文数据库 编辑:程序博客网 时间:2024/06/06 06:49

前言:

所谓的树的直径就是树上两点之间的最大距离

求树的直径有三种方法,三种方法详解


【codeforces 592D】

这一题写过博客的点击打开链接

<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">#include <bits/stdc++.h>using namespace std;#define inf 130000vector<int>adj[inf];int vis[inf];int sizee[inf], dis[inf];void dfs(int p, int u){sizee[u] = 0;if(vis[u]) sizee[u]=1;for(int i = 0; i < adj[u].size(); i++){int v = adj[u][i];if(v!=p){dis[v] = dis[u] + 1;dfs(u, v);sizee[u] += sizee[v];}}}int main(){int n, m;scanf("%d%d", &n, &m);for(int i = 1; i < n; i++){int u, v;scanf("%d%d", &u, &v);adj[u].push_back(v);adj[v].push_back(u);}memset(vis, 0, sizeof(vis));for(int i = 0; i < m; i++){int a;scanf("%d", &a);vis[a] = 1;}memset(dis, 0, sizeof(dis));dfs(-1, 1);int v = -1;for(int i = 1; i <= n; i++){if(vis[i] && (v==-1 || dis[i] > dis[v])) v = i;}memset(dis, 0, sizeof(dis));dfs(-1, v);int sum = 0, sx = 0;for(int i = 1; i <= n; i++){if(sizee[i] && m-sizee[i]>0) sum += 2;if(vis[i]) sx = max(sx, dis[i]);}for(int i = 1; i <= n; i++){if(sx==dis[i] && vis[i] && i<v) v = i; }printf("%d\n%d\n", v, sum-sx);return 0;} </span></span></span>

【POJ  1985 Cow Marathon】

给你一棵树,求树上的两个点之间的最大的距离

先假设1是树的跟,从1开始,一次搜索,求出跟1距离最大的点,记为di

假设di是树的跟,再搜索一次,求出答案

<span style="font-size:14px;"><span style="font-size:14px;">#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <string>#include <vector>using namespace std;int dis[40005], maxn, di;struct node{int id, len;};vector<node>vec[40005];void dfs(int p, int u){for(int i = 0; i < vec[u].size(); i++){node v = vec[u][i];if(p != v.id){dis[v.id] = dis[u] + v.len;if(maxn < dis[v.id]){maxn = dis[v.id];di = v.id;}dfs(u, v.id);}}}int main(){int n, m;while(~scanf("%d%d", &n, &m)){for(int i = 1; i <= n; i++) vec[i].clear();for(int i = 0; i < m; i++){node p;char c[5];int u, v, li;scanf("%d%d%d%s", &u, &v, &li, c);p.id = u, p.len = li;vec[v].push_back(p);p.id = v;vec[u].push_back(p);}memset(dis, 0, sizeof(dis));maxn = -1;dfs(-1, 1);memset(dis, 0, sizeof(dis));dfs(-1, di);printf("%d\n", maxn);}return 0;}</span></span>

【HDU 2196 Computer】

给你一棵树,求树上一点到树上的另一个点最远的距离

这棵树是没有根的

我假设1是整棵树的根节点

第一次dfs求出每个节点到1的距离,记为dis[ i ],求的时候将1的每一棵子树都用相应的数字标记

同时,求出跟1距离最大,第二大的两个子树,距离记为max1, max2,跟1最远的那个点记为d1

然后以d1为根节点,再扫一次,树上每一个点跟d1的距离记为dis2[ i ]

距离最大的子树上的点到树上另一个点最大距离就是max(dis2[ i ], max2 + dis[i])

其它的点 i 到树上另一个点的最大距离就是max(dis2[ i ], max1 + dis[ i ])

注意max1, max2不能在同一棵树上

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <string>#include <vector>using namespace std;#define ll __int64int vis[10005];ll dis[10005], dis2[10005];ll max1, max2;int d1, di;struct node{    int id, len;};vector<node>vec[10005];void dfs(int p, int u, int li){    for(int i = 0; i < vec[u].size(); i++)    {        node v = vec[u][i];        if(v.id != p)        {            dis[v.id] = dis[u]+(ll)v.len;            if(max1 < dis[v.id])            {                if(d1 == li)                {                    max1 = dis[v.id];                    di = v.id;                }                else                {                    max2 = max1;                    max1 = dis[v.id];                    d1 = li;                    di = v.id;                }            }            else if(max1 >= dis[v.id] && max2 < dis[v.id] && d1 != li)            {                max2 = dis[v.id];            }            vis[v.id] = li;            dfs(u, v.id, li);        }    }}void dfs2(int p, int u){    for(int i = 0; i < vec[u].size(); i++)    {        node v = vec[u][i];        if(v.id != p)        {            dis2[v.id] = dis2[u] + (ll)v.len;            dfs2(u, v.id);        }    }}int main(){    int n;    while(~scanf("%d", &n))    {        if(n == 0) break;        if(n == 1)         {            printf("0\n");            continue;        }        for(int i = 1; i <= n; i++) vec[i].clear();        for(int i = 2; i <= n; i++)        {            node p;            scanf("%d%d", &p.id, &p.len);            int d = p.id;            vec[i].push_back(p);            p.id = i;            vec[d].push_back(p);        }        memset(dis, 0, sizeof(dis));        memset(vis, 0, sizeof(vis));        max1 = max2 = 0;        d1 = 0;        for(int i = 0; i < vec[1].size(); i++)        {            node v = vec[1][i];            dis[v.id] = (ll)v.len;            if(max1 < dis[v.id])            {                    max2 = max1;                    max1 = dis[v.id];                    d1 = i+1;                    di = v.id;            }            else if(max1 >= dis[v.id] && max2 < dis[v.id] && d1 != i+1)            {                max2 = dis[v.id];            }            vis[v.id] = i+1;            dfs(1, v.id, i+1);        }        memset(dis2, 0, sizeof(dis2));        dfs2(-1, di);        for(int i = 1; i <= n; i++)        {            if(vis[i] == d1) printf("%I64d\n", max(dis2[i], dis[i]+max2));            else printf("%I64d\n", max(dis2[i], dis[i]+max1));        }    }    return 0;}

【POJ 1383 Labyrinth】

在n*m的方阵中,'#'表示不能走过,'.'表示通路

求方阵中'.'最长是多少

先用bfd处理处相连的两个点

然后两次dfs求出这个联通快的最长距离

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <string>#include <queue>#include <vector>using namespace std;#define inf 1000005char s[1005][1005];int vis[1005][1005], f[4][2] = {0,1, 1,0, 0,-1, -1,0};int li, n, m, tol;int head[inf];int dis[inf], maxn, id;struct Edge{int to, next;}edge[inf*2];struct node{int x, y;};bool is_ok(int x, int y){if(x<m && x>=0 && y<n && y>=0) return true;return false;}void dfs(int p, int u){for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if(p != v){dis[v] = dis[u] + 1;if(maxn < dis[v]){maxn = dis[v];id = v;}dfs(u, v);}}}void add(int a, int b){edge[tol].to = b;edge[tol].next = head[a];head[a] = tol++;}void bfs(int x, int y){int k = li;queue<node>q;node s, e;s.x = x, s.y = y;q.push(s);while(!q.empty()){s = q.front();q.pop();for(int i = 0; i < 4; i++){e = s;e.x += f[i][0];e.y += f[i][1];if(is_ok(e.x, e.y)) {if(vis[e.x][e.y] == -1){li++;vis[e.x][e.y] = li;q.push(e);}if(vis[e.x][e.y] > 0){add(vis[s.x][s.y], vis[e.x][e.y]);}}}}memset(dis, 0, sizeof(dis));maxn = -1;dfs(-1, k);memset(dis, 0, sizeof(dis));dfs(-1, id);}int main(){int t;scanf("%d", &t);while(t--){scanf("%d%d", &n, &m);for(int i = 0; i < m; i++){scanf("%s", s[i]);for(int j = 0; j < n; j++){if(s[i][j] == '#') vis[i][j] = 0;else vis[i][j] = -1;}}int Max = 0;for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){if(vis[i][j] == -1){li=1, tol = 0;memset(head, -1, sizeof(head));vis[i][j] = li;bfs(i, j);Max = max(Max, maxn);}}}printf("Maximum rope length is %d.\n", Max);}return 0;}

0 0
原创粉丝点击