【NOIP2018提高组D2T1】旅行 题解
题目
在这里。
解题思路
关键词:贪心,基环树
考虑
m
=
n
−
1
m=n-1
m=n−1的情况,直接按结点编号大小排序,每次选最小的即可。
设
s
o
n
i
son_i
soni表示
i
i
i的儿子,那么时间复杂度为
O
(
∑
i
=
1
n
s
o
n
i
log
2
s
o
n
i
)
\begin{aligned}O(\sum_{i=1}^n{son_i\log_2^{son_i}})\end{aligned}
O(i=1∑nsonilog2soni)
所以为
O
(
n
log
2
n
)
O(n\log_2^n)
O(nlog2n)。
当
m
=
n
m=n
m=n时,这是一棵基环树,基环树的套路就是删边,然后按照上面的方法做一遍。
可以发现删掉的边一定在环上,所以并查集找环,然后暴力求最小的即可。
时间复杂度为
O
(
n
2
log
2
n
)
O(n^2\log_2^n)
O(n2log2n)。
code
用了许多函数。。。
#include<bits/stdc++.h>
#define N 5005
using namespace std;
int n,m,ans[N],tot;
int s[N],c[N][N],fa[N],pt[N],p[N],vis[N];
int la[N],ne[N<<1],to[N<<1],use[N<<1],cnt;
struct In{
int x,y;
}in[N];
void dfs(int x,int fa){
s[++tot]=x;
for(int i=la[x];i;i=ne[i])
if(to[i]!=fa&&use[i]==0)
dfs(to[i],x);
}
void bl(int x,int en){
if(x==en&&p[0]==0){
for(int i=1;i<=pt[0];i++) p[++p[0]]=pt[i];
return;
}
vis[x]=1;
for(int i=la[x];i;i=ne[i])
if(!vis[to[i]]&&use[i]==0){
pt[++pt[0]]=to[i];
bl(to[i],en);
pt[0]--;
}
}
void addnew(int x,int y){
to[++cnt]=y;
ne[cnt]=la[x];
la[x]=cnt;
}
void cancel(int x,int y){
for(int i=la[x];i;i=ne[i])
if(to[i]==y)
use[i]=1;
for(int i=la[y];i;i=ne[i])
if(to[i]==x)
use[i]=1;
}
void recovery(int x,int y){
for(int i=la[x];i;i=ne[i])
if(to[i]==y)
use[i]=0;
for(int i=la[y];i;i=ne[i])
if(to[i]==x)
use[i]=0;
}
int find(int x){
if(x==fa[x]) return x;
else return fa[x]=find(fa[x]);
}
void copy(){
for(int j=1;j<=n;j++) ans[j]=s[j];
}
void comp(){
for(int j=1;j<=n;j++)
if(s[j]<ans[j]){
copy();
return;
}
else if(s[j]>ans[j]) return;
return;
}
void disconnect(int x,int y){
cancel(x,y);
dfs(1,0);
comp();
recovery(x,y);
}
int main(){
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
c[x][++c[x][0]]=y;
c[y][++c[y][0]]=x;
in[i].x=x;
in[i].y=y;
}
for(int i=1;i<=n;i++){
int len=c[i][0];
sort(c[i]+1,c[i]+len+1);
fa[i]=i;
for(int j=c[i][0];j;j--) addnew(i,c[i][j]);
}
if(m==n-1){
dfs(1,0);
copy();
}
else{
int tx=0,ty=0;
for(int i=1;i<=m;i++){
int rtx=find(in[i].x);
int rty=find(in[i].y);
if(rtx==rty){
tx=in[i].x;
ty=in[i].y;
break;
}
else fa[rtx]=rty;
}
pt[++pt[0]]=tx;
cancel(tx,ty);
bl(tx,ty);
memset(use,0,sizeof(use));
for(int i=1;i<=n;i++) ans[i]=n+1;
disconnect(tx,ty);
for(int i=1;i<p[0];i++){
memset(s,0,sizeof(s));
tot=0;
disconnect(p[i],p[i+1]);
}
}
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
}