[NOIP2018TG]旅行

[NOIP2018TG]旅行

树很简单,对每个点sort儿子,贪心走就行了
基环树呢?
如果是1e5可能不太好做
但是5000的话枚举断边就可以\(n^2\)

#include<bits/stdc++.h>
using namespace std;
const int _=5005;
int re(){
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}
int n,m,cnt,tot,k;
int now[_],ans[_],a[_],b[_],d[_],s[_],sz[_],to[_][_];
bool vis[_],cir[_];
queue<int>q;
void link(int u,int v){
    to[u][++sz[u]]=v;to[v][++sz[v]]=u;
}
void dfs(int u){
    now[++cnt]=u;vis[u]=1;
    for(int i=1;i<=sz[u];i++){
		int v=to[u][i];
		if((u==a[k]&&v==b[k])||(u==b[k]&&v==a[k])||vis[v])
			continue;
		dfs(v);
    }
}
void upd(){
    for(int i=1;i<=n;i++){
		if(ans[i]<now[i])return;
		if(ans[i]>now[i]){
			for(int j=1;j<=n;j++)
				ans[j]=now[j];
			return;
		}
    }
}
void toposort(){
    memset(cir,1,sizeof(cir));
    for(int i=1;i<=m;i++){
		d[a[i]]++;d[b[i]]++;
    }
    for(int i=1;i<=n;i++)
		if(d[i]==1)q.push(i);
    while(!q.empty()){
		int u=q.front();q.pop();
		cir[u]=0;
		for(int i=1;i<=sz[u];i++)
			if(--d[to[u][i]]==1)
				q.push(to[u][i]);
    }
}
int main(){
    memset(ans,63,sizeof(ans));
    n=re(),m=re();
    for(int i=1;i<=m;i++){
		a[i]=re(),b[i]=re();
		link(a[i],b[i]);
    }
    for(int i=1;i<=n;i++)sort(to[i]+1,to[i]+sz[i]+1);
    if(m==n-1){dfs(1);upd();}
    else{
		toposort();
		for(int i=1;i<=m;i++)
			if(cir[a[i]]&&cir[b[i]])s[++tot]=i;
		for(int i=1;i<=tot;i++){
			memset(vis,0,sizeof(vis));
			cnt=0;
			k=s[i];dfs(1);upd();
		}
    }
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);puts("");
    return 0;
}
posted @ 2018-11-28 11:25  sdzwyq  阅读(138)  评论(0编辑  收藏  举报