求树的直径
class Solution {
public:
static const int maxn = 20;
int head[maxn], to[maxn<<1], nex[maxn<<1], tot;
void init() {
memset(head, -1, sizeof(head));
tot = 0;
}
void add(int x, int y) {
to[tot] = y;
nex[tot] = head[x];
head[x] = tot++;
}
bool is[maxn], vis[maxn];
int dis[maxn], maxd;//最长距离maxd
int bfs(int u) {
queue<int> que;
while (!que.empty()) que.pop();
memset(vis, 0, sizeof(vis));
memset(dis, 0, sizeof(dis));
que.push(u);
int max_num = 0;
maxd = 0;
while (!que.empty()) {
int now = que.front(); que.pop();
vis[now] = 1;
for (int i = head[now]; ~i; i = nex[i]) {
int v = to[i];
if(vis[v] || !is[v]) continue;
vis[v] = 1;
dis[v] = dis[now] + 1;
if(dis[v] > maxd) {
maxd = dis[v];
max_num = v;
}
que.push(v);
}
}
return max_num;
}
vector<int> countSubgraphsForEachDiameter(int n, vector<vector<int>>& edges) {
int ans[20];
init();
memset(ans, 0, sizeof(ans));
for (int i = 0; i < edges.size(); i++) {
int u = edges[i][0], v = edges[i][1];
add(u, v);
add(v, u);
}
for (int i = 3; i < (1<<n); i++) {
int cnt = 0, pos;
for (int j = 1; j <= n; j++) is[j] = 0;
for (int j = 0; j < n; j++) {
if(((i>>j)&1)) is[j + 1] = 1, cnt++, pos = j + 1;
}
int u = bfs(pos);
int s = bfs(u);
int tmp = 0;
for (int j = 1; j <= n; j++) if(vis[j]) tmp++;
if(tmp == cnt) ans[maxd]++;
}
vector<int> xx;
for (int i = 1; i < n; i++)
xx.push_back(ans[i]);
return xx;
}
}pp;
//树形dp可以处理负权,两遍bfs和dfs不能,但可以输出路径,而dp不行
//树形dp,找路径带权树上最长的路径长度
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
typedef long long ll;
int head[maxn], to[maxn<<1], nex[maxn<<1], tot, edge[maxn<<1], vis[maxn];
int dp[maxn];
void add(int x, int y, int z) {
to[tot] = y;
edge[tot] = z;
nex[tot] = head[x];
head[x] = tot++;
}
int ans;
void dfs(int x) {
vis[x] = 1;
for (int i = head[x]; ~i; i = nex[i]) {
int v = to[i];
if(vis[v]) continue;
dfs(v);
ans = max(ans, dp[v] + dp[x] + edge[i]);
dp[x] = max(dp[x], dp[v] + edge[i]);
}
}
int main()
{
memset(head, -1, sizeof(head));
int n;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(u, v, w);
}
dfs(1);
printf("%lld\n", (ll)(11 + 10 + ans) * ans / 2);
}
两遍bfs求最长距离,第一遍求出最长的路径上的一个点,第二遍从这个点出发一定是最长的路径
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
typedef long long ll;
int head[maxn], to[maxn<<1], nex[maxn<<1], tot, edge[maxn<<1], vis[maxn];
int dis[maxn], maxd;//最长距离maxd
void add(int x, int y, int z) {
to[tot] = y;
edge[tot] = z;
nex[tot] = head[x];
head[x] = tot++;
}
int bfs(int u) {
queue<int> que;
while (!que.empty()) que.pop();
memset(vis, 0, sizeof(vis));
memset(dis, 0, sizeof(dis));
que.push(u);
int max_num = 0;
maxd = 0;
while (!que.empty()) {
int now = que.front(); que.pop();
vis[now] = 1;
for (int i = head[now]; ~i; i = nex[i]) {
int v = to[i];
if(vis[v]) continue;
vis[v] = 1;
dis[v] = dis[now] + edge[i];
if(dis[v] > maxd) {
maxd = dis[v];
max_num = v;
}
que.push(v);
}
}
return max_num;
}
int main()
{
memset(head, -1, sizeof(head));
int n;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
int u = bfs(1);//第一遍求出的最长路径上的一个点
int s = bfs(u);//
printf("%lld\n", (ll)(11 + 10 + maxd) * maxd / 2);
} 算法竞赛之路 文章被收录于专栏
整理、记录算法竞赛的好题

