一 原题
Your friend is developing a computer game. He has already decided how the game world should look like — it should consist of nn locations connected by mm two-way passages. The passages are designed in such a way that it should be possible to get from any location to any other location.
Of course, some passages should be guarded by the monsters (if you just can go everywhere without any difficulties, then it's not fun, right?). Some crucial passages will be guarded by really fearsome monsters, requiring the hero to prepare for battle and designing his own tactics of defeating them (commonly these kinds of monsters are called bosses). And your friend wants you to help him place these bosses.
The game will start in location ss and end in location tt, but these locations are not chosen yet. After choosing these locations, your friend will place a boss in each passage such that it is impossible to get from ss to ttwithout using this passage. Your friend wants to place as much bosses as possible (because more challenges means more fun, right?), so he asks you to help him determine the maximum possible number of bosses, considering that any location can be chosen as ss or as tt.
The first line contains two integers nn and mm (2≤n≤3⋅1052≤n≤3⋅105, n−1≤m≤3⋅105n−1≤m≤3⋅105) — the number of locations and passages, respectively.
Then mm lines follow, each containing two integers xx and yy (1≤x,y≤n1≤x,y≤n, x≠yx≠y) describing the endpoints of one of the passages.
It is guaranteed that there is no pair of locations directly connected by two or more passages, and that any location is reachable from any other location.
Print one integer — the maximum number of bosses your friend can place, considering all possible choices for ssand tt.
5 5 1 2 2 3 3 1 4 1 5 2
2
4 3 1 2 4 3 3 2
3
二 分析
给一个联通的无向图,顶点之间没有重边。选定两个点s和t,从s到t有一些边是必经的,要求你找一对s和t,使得必经边是最多的,输出其数量。
如果输入的图没有环,那么就是求树的直径(联通且无环的无向图就是一棵树,树上两点之间的路径是唯一的)。所以把图中的环缩成一个点就可以了,如果两个环有交点,那么应当缩成一个点,使用无向图上的tarjan即可。
三 代码
/*
AUTHOR: maxkibble
LANG: c++
PROB: cf 1000E
*/
#include <cstdio>
#include <stack>
#include <vector>
const int maxn = 3e5 + 5;
#define pb push_back
int n, m;
std::vector<int> g[maxn];
void init() {
scanf("%d%d", &n, &m);
while (m--) {
int s, e;
scanf("%d%d", &s, &e);
g[s].pb(e);
g[e].pb(s);
}
}
int clk, dfu[maxn], low[maxn], sz, belong[maxn];
bool inStack[maxn];
std::stack<int> st;
std::vector<std::vector<int> > comp;
void tarjan(int u, int fa) {
dfu[u] = low[u] = ++clk;
st.push(u);
inStack[u] = true;
for (int v: g[u]) {
if (v == fa) continue;
if (!dfu[v]) {
tarjan(v, u);
low[u] = std::min(low[u], low[v]);
} else {
low[u] = std::min(low[u], dfu[v]);
}
}
if (dfu[u] == low[u]) {
std::vector<int> v;
sz++;
while (true) {
int hd = st.top();
st.pop();
inStack[hd] = false;
v.pb(hd);
belong[hd] = sz;
if (hd == u) break;
}
comp.pb(v);
}
}
std::vector<int> g1[maxn];
void buildGraph() {
for (int i = 1; i <= n; i++) {
for (int d: g[i]) {
int s = belong[i], e = belong[d];
if (s == e) continue;
g1[s].pb(e);
}
}
}
int dis[maxn];
void dfs(int u, int fa) {
dis[u] = dis[fa] + 1;
for (int v: g1[u]) {
if (v != fa) dfs(v, u);
}
}
int calcDiag() {
dfs(1, 0);
int furthest = 1;
for (int i = 1; i <= sz; i++) {
if (dis[i] > dis[furthest]) furthest = i;
}
dfs(furthest, 0);
int ans = 0;
for (int i = 1; i <= sz; i++) ans = std::max(ans, dis[i]);
return ans - 1;
}
void solve() {
for (int i = 1; i <= n; i++) {
if (!dfu[i]) tarjan(i, 0);
}
buildGraph();
printf("%d\n", calcDiag());
}
int main() {
init();
solve();
return 0;
}

这是一篇关于计算机游戏设计的文章,讲述了如何在由n个地点和m条双向通道构成的游戏世界中,确定最多数量的必须战斗的Boss。游戏开始和结束地点未定,目标是确保从起点到终点必须通过放置了Boss的通道。文章首先介绍了问题背景,然后分析了问题本质是求无向图中两点间最长路径(树的直径),最后提供了可能的解决方案——利用Tarjan算法处理环并寻找最远路径。
224

被折叠的 条评论
为什么被折叠?



