• 【ybtoj】【最小生成树】生物进化


    题意

    题解

    这题不是特别难,但是有思维陷阱

    题里不断给出各种祖先差异程度的计算方法(其实就是树上距离的求法),不禁让我想着根据 Da+Db=Dc这种形式来判断祖先关系,然后就没有然后了

    实际上,不用管加和判断这些东西,因为每次加入最小生成树的都是直系边(因为直系边最短),而当加完直系边之后由于端点都被走过,所以不会再加入非直系边,就不用考虑那些乱七八糟的祖先关系

    由于第一次写 prim 模板,所以细节在代码里标注了一下

    关键:跳出常规思维,发现隐含条件

    代码

    生物进化
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define mp make_pair
    #define pr pair<int,int>
    priority_queue<pr,vector<pr>,greater<pr> >q; 
    const int INF = 0x3f3f3f3f,N = 105;
    int n,ecnt=-1,head[N*N<<1],dis[N],vis[N],fa[N];
    struct edge
    {
    	int nxt,to,w;
    }a[N*N<<1];
    void add(int x,int y,int w)
    {
    	a[++ecnt].nxt=head[x];
    	a[ecnt].to=y;
    	a[ecnt].w=w;
    	head[x]=ecnt;
    }
    void prim()
    {
    	memset(dis,0x3f,sizeof(dis));
    	dis[1]=0;
    	q.push(mp(0,1));
    	while(!q.empty())
    	{
    		int u=q.top().second;q.pop();
    		if(vis[u]) continue;
    		vis[u]=1;
    		for(int i=head[u];~i;i=a[i].nxt)
    		{
    			int v=a[i].to;
    			if(vis[v]) continue;//注意这里判断不能走回父亲 
    			if(dis[v]>a[i].w)
    			{
    				//printf("(u,v):%d %d
    ",u,v);
    				fa[v]=u;//这个地方记录直系祖先即可 
    				dis[v]=a[i].w;
    				q.push(mp(dis[v],v));
    			}
    		}
    	}
    }
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		for(int j=1,x;j<=n;j++)
    		{	
    			scanf("%d",&x);
    			if(i!=j) add(i,j,x),add(j,i,x);//注意建双向边,去除自环 
    		}
    	prim();
    	for(int i=1;i<n;i++)	
    		printf("%d
    ",fa[i+1]); 
    	return 0;
    }
    
  • 相关阅读:
    Mybatis源码中最重要的几个类
    学习爬虫-运营商积分
    IntelliJ IDEA 最新版 2019.2.4 激活 (持续更新)(含windows和Mac)
    归并排序之求小和
    归并排序
    理解递归
    插入排序
    对数器
    冒泡排序
    mysql 数据库名称,中间带有中划线问题
  • 原文地址:https://www.cnblogs.com/conprour/p/15237511.html
Copyright © 2020-2023  润新知