题解 P5022 【旅行】

题解 P5022 【旅行】

题目链接

一道基环树的题记得我当时在考场连dfs都没想到(我真的是太弱了QAQ)

这道题知道思路其实很简单,当n = m - 1时,图是一个树,直接从第一个点dfs就可以得到答案,n = m时说明图里有一个环,删掉环上的任意一条边就可以让图变成一个数,枚举删除那一条边得到的答案字典序最小即可。

我们老师刚学图就让我们做这道题,总之我觉得用来练习图的基本操作是极好的。这道题我大概交了十几遍才过,因为dfs要求先访问编号最小的节点,所以我第一次一上来用邻接矩阵存图,结果T飞了想想为什么,后来吭哧吭哧自学了邻接链表结果忘了排序......最后做足了功课上std,又T了三个点很明显为什么

仔细琢磨了一下发现一个优化,在n = m时,当我们删除了一条边开始dfs(答案存在res数组里),如果我们发现res[u] > ans[u], 则res一定不比ans优,可以直接跳出,然后你就可以AC最后三个点了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define ll long long
#define N 5005
using namespace std;

int n, m, tot, vis[N], ans[N], res[N], inp[N][2];
bool ian = 0; //代表res中的答案是否比ans优

vector < int > mp[N];

inline int read()
{
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}

void addedge(int x, int y)
{
	mp[x].push_back(y);
	mp[y].push_back(x);
}

void dfs(int x, int d1, int d2) //d1 d2 表示删除的边连接的节点
{
	vis[x] = true;
	res[++tot] = x;
	if (x < ans[tot]) ian = true; //如果res[x] < ans[x],则无论res后面是什么,res都一定比ans优
	if (x > ans[tot] && !ian) { vis[x] = false; return; } //如果res[x] > ans[x] 且x前面的答案都一样,则res一定没有ans优
	int l = mp[x].size();
	for (int i = 0; i < l; i++)
	{
		if (!vis[mp[x][i]] && !((x == d1 && mp[x][i] == d2) || (x == d2 && mp[x][i] == d1)))
			dfs(mp[x][i], d1, d2);
	}
	vis[x] = false;//别忘了把值赋回去
}

int main()
{
	memset(ans, 0x3f3f3f, sizeof(ans));
	n = read(), m = read();
	for (int i = 1; i <= m; i++)
		addedge(inp[i][0] = read(), inp[i][1] = read());
	for (int i = 1; i <= n; i++)
		sort(mp[i].begin(), mp[i].end()); //一定别忘了排序,不然dfs出来的不一定字典序最小
	if (n == m)//有环
	{
		for (int i = 1; i <= m; i++)//枚举删边
		{
			tot = 0, ian = false;
			dfs(1, inp[i][0], inp[i][1]);
			if (tot != n) continue;
			int flag = false; //res比ans更优
			for (int i = 1; i <= n; i++)
			{
				if (res[i] < ans[i]) { flag = true; break; }
				else if (res[i] > ans[i]) { break; }
			}//看看ans和res哪一个更优
			if (flag)//如果res更优则把res赋给ans
				for (int i = 1; i <= n; i++)
					ans[i] = res[i];
		}
	}
	else//没有环
	{
		dfs(1, 0, 0);
		for (int i = 1; i <= n; i++)
			ans[i] = res[i];
	}
	for (int i = 1; i <= n; i++)
		cout << ans[i] << " ";//输出答案
	return 0;
}

19.08.18

posted @ 2019-10-04 16:13  Yuanqi_Yu  阅读(174)  评论(0)    收藏  举报