演算法
對於一棵樹的情況, dfs + 貪心選取顯然是正確的
對於基環樹的情況
我們觀察到城市不能重複行走
所以長為 \(L\) 的環最多隻會被訪問 \(L - 1\) 條邊
列舉斷邊, 再跑 dfs + 貪心即可
程式碼
#include <bits/stdc++.h>
const int MAXN = 5e3 + 20;
int n, m;
std::vector<int> e[MAXN], ans;
int U[MAXN], V[MAXN];
class Subtast_1
{
private:
public:
bool vis[MAXN];
int res[MAXN];
void dfs(int u)
{
ans.push_back(u), vis[u] = true;
for (int i = 0; i < e[u].size(); ++i)
{
int v = e[u][i];
if (!vis[v])
dfs(v);
}
}
void solve()
{
dfs(1);
for (int i = 0; i < ans.size(); ++i)
std::cout << ans[i] << " ";
}
} s1;
class Subtask_2
{
private:
public:
int res[MAXN], ans[MAXN];
bool cmp()
{
for (int i = 1; i <= n; ++i)
if (res[i] < ans[i])
return true;
else if (res[i] > ans[i])
return false;
return false;
}
int Delete_u, Delete_v, Past_Cnt = 0;
bool NotbeDelete(int u, int v)
{
if ((u == Delete_u && v == Delete_v) || (u == Delete_v && v == Delete_u))
return false;
return true;
}
bool vis[MAXN];
void dfs(int u)
{
vis[u] = true, res[++Past_Cnt] = u;
for (int i = 0; i < e[u].size(); ++i) {
int v = e[u][i];
/*不跑刪邊*/
if (!vis[v] && NotbeDelete(u, v))
dfs(v);
}
}
void solve()
{
for (int i = 1; i <= m; ++i)
{
int u = U[i], v = V[i];
memset(res, 0, sizeof(res));
memset(vis, false, sizeof(vis));
Past_Cnt = 0;
Delete_u = u, Delete_v = v;
/*判斷刪掉的這條邊在不在環上*/
dfs(1);
if (Past_Cnt < n)
continue;
bool Best = cmp();
if (ans[1] == 0 || Best)
memcpy(ans, res, sizeof(res));
}
for (int i = 1; i <= n; ++i)
std::cout << ans[i] << " ";
}
} s2;
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1, u, v; i <= m; ++i) {
scanf("%d %d", &u, &v);
e[u].push_back(v), e[v].push_back(u), U[i] = u, V[i] = v;
}
for (int i = 1; i <= n; ++i)
sort(e[i].begin(), e[i].end());
if (m == n - 1)
s1.solve();
else if (m == n)
s2.solve();
return 0;
}
總結
斷邊後, 基環樹可按照樹的方式處理