樹形dp題集之樹的直徑

前言:

所謂的樹的直徑就是樹上兩點之間的最大距離

求樹的直徑有三種方法,三種方法詳解


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 130000
vector<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 __int64
int 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 1000005
char 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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章