[NOIP2018 提高组] 旅行

本文介绍了如何使用深度优先搜索算法解决NOIP2018竞赛中的旅行-洛谷问题,涉及对图中点间路径的字典序最小求解,包括两种情况:全连通图和部分可达图的处理方法以及vector在代码实现中的应用。
摘要由CSDN通过智能技术生成

目录

1. 题目:

2. 思路

3. 代码解释:

1. 输入

2. 分类讨论:

1)当整个图中每个点之间都是有一条直通的路线时

2) 不是每个点都能直达图中的任何一个点时

3. 输出

3. 完整代码:


1. 题目:

[NOIP2018 提高组] 旅行 - 洛谷

仔细看完题目之后,我们发现就是求路径的字典序最小

注意!!!求字典序最小而不是求路径最小值

2. 思路

深度优先搜索,我们先进行预处理,求出每一个点可以到的其他点都是什么,然后在主函数中,逐个判断字典序的大小,最后输出

3. 代码解释:

1. 输入

    cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int u,v;
		cin>>u>>v;
		a[u].push_back(v);
		a[v].push_back(u);
		edge[i].u=u;
		edge[i].v=v;
	}
	for(int i=1;i<=n;i++)
	{
		sort(a[i].begin(),a[i].end());
    }

由小到大排序,便于后面比较字典序且搜索时保证由小到大

2. 分类讨论:

1)当整个图中每个点之间都是有一条直通的路线时

只需要直接输出各个点相连的点中较小的点编号

主函数:

    if(m==n-1)
	{
		cout<<1<<" ";
		flag[1]=1;
		dfs2(1);
	}

dfs:

void dfs2(int x)
{
	for(auto i:a[x])
	{
		if(flag[i]==0)
		{
			flag[i]=1;
			cout<<i<<" ";
			dfs2(i);
		}
	}
}

2) 不是每个点都能直达图中的任何一个点时

dfs:

void dfs(int x,int u,int v)
{
	flag[x]=1;
	path[++cnt]=x;
	for(auto i:a[x])
	{
		if(!(flag[i]==1 || x==u&&i==v || x==v&&i==u))
		{
			dfs(i,u,v);
		}
	}
}

标记这个点表示已经经过

路径编号记录path 记录下这个点

循环找与他相邻的点,如果这个点没有被标记过 或者 都没有到达终点并且与现在所在连接的两个点不同时,dfs

主函数:

    memset(ans,0x3f,sizeof(ans));
	for(int i=1;i<=n;i++)
	{
		memset(flag,0,sizeof(flag));
		cnt=0;
		state=0;
	    dfs(1,edge[i].u,edge[i].v);
		if(cnt==n )
		{
			int f=0;
			for(int j=1;j<=n;j++)
			{
				if(path[j]>ans[j])
				{
					f=1;
					break;
				}
				else if(path[j]<ans[j])
				{
					f=-1;
					memcpy(ans,path,sizeof(ans));
					break;
				}
			}
		

预处理完后,如果cnt==n,说明每个点都已经走过了

循环,找字典序(一位一位找)字典序小的就memcpy(A,B,sizeof(A)) 即将B字符串赋值给A,

记录字典序最小的

3. 输出

	    for(int i=1;i<=n;i++)
		{
			cout<<ans[i]<<" ";
		}	

3. 完整代码:

#include<bits/stdc++.h>
using namespace std;
vector<int>  a[5005];
int flag[5005];
int path[5005];
int cnt=0; 
int ans[5005];
int state;
struct node 
{
	int u,v;
}edge[5005];  
void dfs(int x,int u,int v)
{
	flag[x]=1;
	path[++cnt]=x;
	for(auto i:a[x])
	{
		if(!(flag[i]==1 || x==u&&i==v || x==v&&i==u))
		{
			dfs(i,u,v);
		}
	}
}
void dfs2(int x)
{
	for(auto i:a[x])
	{
		if(flag[i]==0)
		{
			flag[i]=1;
			cout<<i<<" ";
			dfs2(i);
		}
	}
}
int n,m;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int u,v;
		cin>>u>>v;
		a[u].push_back(v);
		a[v].push_back(u);
		edge[i].u=u;
		edge[i].v=v;
	}
	for(int i=1;i<=n;i++)
	{
		sort(a[i].begin(),a[i].end());
	}
	if(m==n-1)
	{
		cout<<1<<" ";
		flag[1]=1;
		dfs2(1);
	}
	else
	{
		memset(ans,0x3f,sizeof(ans));
		for(int i=1;i<=n;i++)
		{
			memset(flag,0,sizeof(flag));
			cnt=0;
			state=0;
			dfs(1,edge[i].u,edge[i].v);
			if(cnt==n )
			{
				int f=0;
				for(int j=1;j<=n;j++)
				{
					if(path[j]>ans[j])
					{
						f=1;
						break;
					}
					else if(path[j]<ans[j])
					{
						f=-1;
						memcpy(ans,path,sizeof(ans));
						break;
					}
				}
			}
		}
		//输出 
		for(int i=1;i<=n;i++)
		{
			cout<<ans[i]<<" ";
		}		
	}	
	return 0;
 } 

最后附上动态数组vector用法:【语法】vector-CSDN博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值