L2-038 病毒溯源 (25 分) 搜索
Published on 2022-11-17 23:02 in 暂未分类 with 林动

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 @   林动  阅读(30)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
    · 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
    · 【译】Visual Studio 中新的强大生产力特性
    · 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
    · 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
    点击右上角即可分享
    微信分享提示