题意
题解
这题不是特别难,但是有思维陷阱
题里不断给出各种祖先差异程度的计算方法(其实就是树上距离的求法),不禁让我想着根据 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;
}