0
点赞
收藏
分享

微信扫一扫

GPLT L2-038 病毒溯源

白衣蓝剑冰魄 2022-04-19 阅读 84
c++算法

题面

https://pintia.cn/problem-sets/994805046380707840/problems/1386335159927652361

思路

该题目抽象出来是:“有一个图,你需要找到最长路径,如果有多条最长路径,输出字典序最小的一条。题目保证没有回路。”
做法:

  • 用领接表存储图
  • 用dfs遍历图,找到最长字典序最小的路径

实现

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1e4 + 10;
int h[N], e[N], ne[N], ans[N], temp[N], idx, cnt, n;
bool st[N];

bool cmp()//长度相同情况下,判断答案是否最小
{
	for(int i = 0; i <= cnt; i ++)
		if(ans[i] != temp[i])
		{
			if(ans[i] > temp[i]) return true;
			else return false;
		}

	return false;
}

void dfs(int u, int l)
{
	temp[l] = u, st[u] = true;//放置第l个元素,如果不进行记忆化搜索,会被第五个测试点卡掉
	if(h[u] == -1)//表明这条路走到头了
	{
		if(l > cnt || (l == cnt && cmp()) )
		{
			memcpy(ans, temp, sizeof(int) * (l + 1));
			cnt = l;
		}
		return;
	}

	for(int i = h[u]; ~i; i = ne[i])
	{
		int j = e[i];
		dfs(j, l + 1);
	}
}

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

int main()
{
	memset(h, -1, sizeof h);

	cin >> n;
	for(int i = 0; i < n; i ++)
	{
		int k;
		cin >> k;
		for(int j = 1; j <= k; j ++)
		{
			int t;
			cin >> t;
			add(i, t);
		}
	}

	for(int i = 0; i < n; i ++)
		if(!st[i]) dfs(i, 0);//如果该点遍历过,说明前面从某个点起的路径,比从当前点起的路径长

	cout << cnt + 1 << endl;
	for(int i = 0; i <= cnt; i ++) cout << ans[i] << " \n"[i == cnt];

	return 0;
}
举报

相关推荐

0 条评论