题意:60pts:给定一棵树,从某一个点出发,允许沿着来的路径返回。每次访问新城市,将标号加入到序列中,求字典序最小的序列。
另40pts:给定一棵基环树,从某一个点出发,允许沿着来的路径返回。每次访问新城市,将标号加入到序列中,求字典序最小的序列。
首先任何情况下都要先从1出发。
树的部分很好解决,每次从所在节点的子节点中选出最小的,并遍历其子树。
基环树的部分,可以发现这个环一定不会每条边都走,因此暴力枚举哪条边不走即可。注意判断删边之后的连通性
n=5000可过
using namespace std;
const int MAXN = 5005;
const int MAXM = 5005;
int n, m, num;
int ban;
int fir[MAXN], nxt[MAXM << 1], to[MAXM << 1], cnt;
int vis[MAXN];
int ans[MAXN], now[MAXN];
int son[MAXN][MAXN];
struct Edge{
int a, b;
}e[MAXM];
inline int read(){
int k = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){k = k * 10 + ch - '0'; ch = getchar();}
return k * f;
}
inline void add_edge(int a, int b){
to[cnt] = b; nxt[cnt] = fir[a]; fir[a] = cnt++;
}
void dfs(int u, int f){
now[++num] = u;
vis[u] = true;
for(int i = fir[u]; i != -1; i = nxt[i]){
int v = to[i];
if(vis[v]) continue;
if(e[ban].a == u && e[ban].b == v) continue;
if(e[ban].a == v && e[ban].b == u) continue;
son[u][++son[u][0]] = v;
}
sort(son[u] + 1, son[u] + son[u][0] + 1);
for(int i = 1; i <= son[u][0]; i++){
dfs(son[u][i], u);
}
}
int main(){
memset(fir, -1, sizeof(fir)); cnt = 0;
n = read(), m = read();
for(int i = 1; i <= m; i++){
int a = read(), b = read();
e[i] = (Edge){a, b};
add_edge(a, b);
add_edge(b, a);
}
if(m == n - 1){
dfs(1, 0);
for(int j = 1; j <= n; j++){
ans[j] = now[j];
}
}
else{
ans[1] = 1e9;
for(int i = 1; i <= n; i++){
num = 0;
memset(vis, 0, sizeof(vis));
ban = i;
for(int j = 1; j <= n; j++) son[j][0] = 0;
dfs(1, 0);
if(num < n) continue;
for(int j = 1; j <= n; j++){
if(now[j] > ans[j]) break;
if(now[j] < ans[j]){
for(int k = 1; k <= n; k++){
ans[k] = now[k];
}
break;
}
}
}
}
for(int i = 1; i <= n; i++){
printf("%d ", ans[i]);
}
return 0;
}```