旅行

旅行


这道题再次发扬了noip看范围过数据( 骗分)的风范
对于前%60的数据可以适用于瞎搞的数据结构加上一个贪心dfs轻松水过

#include<bits/stdc++.h>
using namespace std;
int m,n;
int vis[5002];
int u,v;
struct node
{
    int totl;//数量 
    int reach_[5001];//接通点 
}a[5001];
void dfs(int nowl)
{
    sort(a[nowl].reach_+1,a[nowl].reach_+a[nowl].totl+1);
    for(int i=1;i<=a[nowl].totl;++i)
    {
        if(!vis[a[nowl].reach_[i]])
        {
            vis[a[nowl].reach_[i]]=1;
            cout<<a[nowl].reach_[i]<<" ";
            dfs(a[nowl].reach_[i]);
        }
    }
}
int main()
{
    cin>>n>>m;
    if(m==n-1)
    {
    for(int i=1;i<=m;++i)
    {
        cin>>u>>v;
    a[u].reach_[++a[u].totl]=v;
    a[v].reach_[++a[v].totl]=u;
    }
    cout<<"1 ";
    vis[1]=1;
    dfs(1);
    }
}

嗯…nice~
对于临接链表在这里存图非常不爽
由于你需要使用sort对当前节点进行处理,使用贪心(走最小字典序)
所以你需要再开一个数组进行存入以便于排序,那么这个数组就显得至关重要,数组开大了就TLE,而且也不能太小,所以我们就尝试去开成50左右,至少不会超时间 (但别人想卡死你那就没招了)由于不太会用vector之类的矩阵存图我还是用邻接链表;
同时给大家安利一波register int;
这个手动优化可以加快for循环的速度;
对于测试数据最后一个点大概快了100ms左右;
下面进入正题…
操作前看一波数据范围n==m;
基环树!!!
对于这种数据结构第一件事就是找环;
之后就是依次断开所有的链去暴搜;
代码如下

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rei register int
using namespace std;
int n,m;int stack[50001];int dfn[50001];
int ans[50001],top;int times,cnt,stop,flag;
int tot,head[50001];int dad[50001];
struct node
{
	int ver;
	int next;
}edge[50001];
bool cmp(int x,int y)
{
	return x<y;
}
inline void add(int x,int y)
{
	edge[++tot].next=head[x];
	edge[tot].ver=y;
	head[x]=tot;
}
inline void dfs1(int x,int fa)
{
	ans[++top]=x;
	int vis[55];memset(vis,0,sizeof(vis));
	int num=0;
	for(rei i=head[x];i;i=edge[i].next)
	{
		int y=edge[i].ver;
		if(fa==y) continue;
		vis[++num]=y;
	}
	sort(vis+1,vis+num+1,cmp);
	for(rei i=1;i<=num;++i)
		dfs1(vis[i],x);
}
inline void find_loop(int x)
{
	dfn[x]=++times;
	for(rei i=head[x];i;i=edge[i].next)
	{
		int y=edge[i].ver;
		if(y==dad[x]) continue;
		if(dfn[y])
		{
			if(dfn[y]<dfn[x]) continue;
			stack[++cnt]=y;
			for(;y!=x;y=dad[y]) stack[++cnt]=dad[y];
		}
		else dad[y]=x,find_loop(y);
	}
}
inline void dfs2(int x,int fa,int ban1,int ban2)
{
	if(stop) return;
	top++;
	if(x<ans[top]) flag=1;
	if(x>ans[top]&&!flag) {	stop=1;return ;}//剪枝如果本次dfs所确定的顺序大于之前的直接return
	if(flag) ans[top]=x;
	int vis[55],num=0,ban=0;
	memset(vis,0,sizeof(vis));
	//下面是枚举断链的精髓
	if(x==ban1) ban=ban2;
	else if(x==ban2) ban=ban1;
	for(rei i=head[x];i;i=edge[i].next)
	{
		int y=edge[i].ver;
		if(y==fa) continue;
		if(y!=ban) vis[++num]=y;
	}
	sort(vis+1,vis+num+1,cmp);
	for(rei i=1;i<=num;++i)
	dfs2(vis[i],x,ban1,ban2);
}
int main()
{
	cin>>n>>m;
	int u,v;
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d",&u,&v);
		add(u,v); add(v,u);
	}
	if(m==n-1)
	{
		dfs1(1,0);
		for(int i=1;i<=n;++i)
		cout<<ans[i]<<" ";
	}
	if(n==m)
	{
		int vis[5001];memset(vis,0,sizeof(vis));
		memset(ans,0x3f,sizeof(ans));//初始化
		find_loop(1);
		for(rei i=1;i<cnt;++i)
		{
		flag=top=stop=0;
		dfs2(1,1,stack[i],stack[i+1]);
		}
		for(rei i=1;i<=n;++i) cout<<ans[i]<<" ";
	}
	return 0;
}

PS:第一次写题解and本题代码思路有对别人的借鉴;
我希望在细节上对大家有帮助

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值