L2-038 病毒溯源 (25 分) 搜索

我是绿色病毒容易发生变异。某种病毒可以通过突变产生若干变异的毒株,而这些变异的病毒又可能被诱发突变产生第二代变异,如此继续不断变化。

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

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

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

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

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

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

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

注:我们称序列 { a
1

,⋯,a
n

} 比序列 { b
1

,⋯,b
n

} “小”,如果存在 1≤k≤n 满足 a
i

=b
i

对所有 i<k 成立,且 a
k

<b
k

输入样例:
10
3 6 4 8
0
0
0
2 5 9
0
1 7
1 2
0
2 3 1
输出样例:
4
0 4 9 1

最近在学markdown语法😁😁😁😁😁

只要对根节点进行搜索即可,非根节点搜索无意义,会超时

搜索策略:bfs和dfs皆可,只要找到长度最长的那个路径,并且是第一次搜索到的,即为答案,dfs还是要简单一些的
记录路径:使用一个记录父节点的数组,这样只要记录最长路径的末尾结点即可反推回整条路径

自顶向下搜索:10ms

#include <bits/stdc++.h>

using namespace std;
const int N=10005;

vector<int> v[N];
int last=-1;
int f[N];
int ans;

void dfs(int t,int u)
{
	if(u>ans)
	{
		last=t;
		ans=u;
	}
	for(int i=0;i<v[t].size();++i)
	{
		int x=v[t][i];
		dfs(x,u+1);
	}
}

int main()
{
	int n;cin>>n;
	for(int i=0;i<n;++i)f[i]=-1;
	for(int i=0;i<n;++i)
	{
		int k;cin>>k;
		for(int j=0;j<k;++j)
		{
			int x;cin>>x;
			f[x]=i;
			v[i].push_back(x);
		}
	}
	for(int i=0;i<n;++i)sort(v[i].begin(),v[i].end());
	for(int i=0;i<n;++i)
	{
		if(f[i]==-1)dfs(i,1);
	}
	cout<<ans<<endl;
	stack<int> s;
	while(last!=-1)
	{
		s.push(last);
		last=f[last];
	}
	while(s.size())
	{
		if(s.size()!=1)
		{
			cout<<s.top()<<" ";s.pop();
		}
		else 
		{
			cout<<s.top();s.pop();
		}
	}
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=100005,M=N;
bool flag;
int f[N],d[N],u,ma,n,a[N],ans;
int e[M],ne[M],h[N],idx;
void add(int a,int b){
	e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void dfs(int u,int t){
	if(t>ma){
		ma=t;
		ans=u;
	}
	for(int i=h[u];i!=-1;i=ne[i]){
		int j=e[i];
		dfs(j,t+1);
	}
}
void out(int x){
	if(f[x]!=-1)out(f[x]);
	if(x!=ans)cout<<x<<" ";
	else cout<<x;
}
int main()
{
	cin>>n;
	memset(f,-1,sizeof f);
	memset(h,-1,sizeof h);
	for(int i=0;i<n;++i){
		int k;cin>>k;
		for(int j=0;j<k;++j)cin>>a[j];
		sort(a,a+k,greater<int>());
		for(int j=0;j<k;++j){
			int x=a[j];
			f[x]=i;
			add(i,x);
		}
	}
	for(int i=0;i<n;++i)if(f[i]==-1)u=i;
	dfs(u,1);
	cout<<ma<<endl;
	out(ans);
	return 0;
}
一遍自底向上,找最大值和根节点,一遍自顶向下确定路径:

不建立图:暴力判断子节点75ms

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
bool flag;
int f[N],d[N],u,ma,n,a[N];
void out(){
	for(int i=1;i<=ma;++i){
		if(i!=ma)
		cout<<a[i]<<" ";
		else cout<<a[i];
	}
}
void dfs(int u,int t){
	if(flag)return;
	a[t]=u;
	if(t==ma){
		flag=true;
		out();
		return;
	}
	for(int i=0;i<n;++i){
		if(f[i]==u)dfs(i,t+1);
	}
}
int find(int x){
	if(f[x]==-1){
		u=x;
		return d[x]=1;
	}
	if(d[x])return d[x];
	return d[x]=find(f[x])+1;
}
int main()
{
	cin>>n;
	memset(f,-1,sizeof f);
	for(int i=0;i<n;++i){
		int k;cin>>k;
		while(k--){
			int x;cin>>x;
			f[x]=i;
		}
	}
	for(int i=0;i<n;++i){
		find(i);
		ma=max(ma,d[i]);
	}
	cout<<ma<<endl;
	dfs(u,1);
	return 0;
}

建图:10ms

#include<bits/stdc++.h>
using namespace std;
const int N=10005;
vector<int> v[N];
int ma,u,f[N],d[N],a[N];
bool flag;
int find(int x){
	if(f[x]==-1)return d[x]=1;
	if(d[x])return d[x];
	return d[x]=find(f[x])+1;
}
void out(){
	for(int i=1;i<=ma;++i){
		if(i==1)cout<<a[i];
		else cout<<" "<<a[i];
	}
}
void dfs(int u,int t)
{
	if(flag)return;
	a[t]=u;
	if(t==ma){
		flag=true;
		out();
	}
	for(int i=0;i<v[u].size();++i){
		dfs(v[u][i],t+1);
	}
}
int main()
{
	int n;cin>>n;
	memset(f,-1,sizeof f);
	for(int i=0;i<n;++i){
		int k;cin>>k;
		int a[k];
		for(int j=0;j<k;++j)cin>>a[j];
		sort(a,a+k,less<int>());
		for(int j=0;j<k;++j){
			int x=a[j];
			f[x]=i;
			v[i].push_back(x);
		}
	}
	for(int i=0;i<n;++i){
		if(find(i)>ma){
			ma=d[i];
		}
		if(d[i]==1)u=i;
	}
	cout<<ma<<endl;
	dfs(u,1);
	return 0;
}
自底向上搜索:200ms
#include <bits/stdc++.h>

using namespace std;
const int N=10005;
int f[N],d[N],n,k,x,ma,p; 
vector<int> v[N];
int find(int x)
{
	if(d[x])return d[x];
	if(f[x]==-1)return d[x]=1;
	d[f[x]]=find(f[x]);
	return d[x]=d[f[x]]+1;
}
void dfs(int x)
{
	if(f[x]!=-1)dfs(f[x]);
	v[p].push_back(x);
}
int main()
{
	cin>>n;
	memset(f,-1,sizeof f); 
	for(int i=0;i<n;++i){
		cin>>k;
		while(k--){
			int x;cin>>x;f[x]=i;
		}
	}
	for(int i=0;i<n;++i){
		d[i]=find(i);
		if(ma<d[i])ma=d[i];
	} 
	cout<<ma<<endl;
	for(int i=0;i<n;++i){
		if(d[i]==ma){
			dfs(i);
			p++;
		}
	}
	sort(v,v+p);
	for(int i=0;i<ma;++i){
		if(i!=ma-1)cout<<v[0][i]<<" ";
		else cout<<v[0][i];
	}
	return 0;
}
posted @ 2022-11-17 23:02  林动  阅读(19)  评论(0编辑  收藏  举报