前言:
所谓的树的直径就是树上两点之间的最大距离
求树的直径有三种方法,三种方法详解
这一题写过博客的点击打开链接
<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>
给你一棵树,求树上的两个点之间的最大的距离
先假设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>
给你一棵树,求树上一点到树上的另一个点最远的距离
这棵树是没有根的
我假设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;
}
在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;
}