F_JustWei's Studio.

L2-038 病毒溯源

字数统计: 779阅读时长: 3 min
2021/04/28 Share

L2-038 病毒溯源

现给定一些病毒之间的变异关系,要求你找出其中最长的一条变异链。

在此假设给出的变异都是由突变引起的,不考虑复杂的基因重组变异问题 —— 即每一种病毒都是由唯一的一种病毒突变而来,并且不存在循环变异的情况。

输入格式:

输入在第一行中给出一个正整数 N(≤104),即病毒种类的总数。于是我们将所有病毒从 0 到 N−1 进行编号。

随后 N 行,每行按以下格式描述一种病毒的变异情况:

1
k 变异株1 …… 变异株k

其中 k 是该病毒产生的变异毒株的种类数,后面跟着每种变异株的编号。第 i 行对应编号为 i 的病毒(0≤i<N)。题目保证病毒源头有且仅有一个。

输出格式:

首先输出从源头开始最长变异链的长度。

在第二行中输出从源头开始最长的一条变异链,编号间以 1 个空格分隔,行首尾不得有多余空格。如果最长链不唯一,则输出最小序列。

注:我们称序列 { a1,⋯,an } 比序列 { b1,⋯,bn } “小”,如果存在 1≤k≤n 满足 ai=bi 对所有 i<k 成立,且 ak<bk

输入样例:

1
2
3
4
5
6
7
8
9
10
11
10
3 6 4 8
0
0
0
2 5 9
0
1 7
1 2
0
2 3 1

输出样例:

1
2
4
0 4 9 1

思路:

邻接表+回溯法。(2021年 L2 最难一题)

C++程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <map>
#include <set>
#include <regex>
#include <stack>
#include <queue>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int dir[4][2] = { {1,0} ,{-1,0},{0,1},{0,-1} };
void dfs(int index, int cnt, int& maxCnt, vector<int>& v, vector<int>& ans, vector<vector<int>>& lists) {
//当前路径长度大于最大路径长度
//更新并记录
if (cnt > maxCnt) {
maxCnt = cnt;
ans = v;
}
//遍历所有路径
for (int t : lists[index]) {
v.push_back(t);
dfs(t, cnt + 1, maxCnt, v, ans, lists);
v.pop_back();
}
}
int main(){
int n;

cin >> n;

//标记变异株有没有出现,没有出现那个就是源头
vector<bool> exists(n, false);
//邻接表
vector<vector<int>> lists(n);
for (int i = 0; i < n; i++) {
int k;
cin >> k;
while (k--) {
int t;
cin >> t;
exists[t] = true;
lists[i].push_back(t);
}
//每个序列都从小到大排序的话
//找到的第一个最长路径必然是最小路径
sort(lists[i].begin(), lists[i].end());
}
//找源头
int sourcePos = 0;
for (int i = 0; i < n; i++) {
if (exists[i] == false) {
sourcePos = i;
break;
}
}
//回溯
int cnt = 1;
int maxCnt = 0;
vector<int> v;
vector<int> ans;
dfs(sourcePos, cnt, maxCnt, v, ans, lists);
//输出
cout << maxCnt << endl;
cout << sourcePos;
for (int i = 0; i < ans.size(); i++) {
cout << " " << ans[i];
}

return 0;
}
/*

*/
CATALOG
  1. 1. L2-038 病毒溯源
    1. 1.0.1. 输入格式:
    2. 1.0.2. 输出格式:
    3. 1.0.3. 输入样例:
    4. 1.0.4. 输出样例:
    5. 1.0.5. 思路:
    6. 1.0.6. C++程序: