【ybtoj】【最小生成樹】生物進化
阿新 • • 發佈:2021-09-07
題意
題解
這題不是特別難,但是有思維陷阱
題裡不斷給出各種祖先差異程度的計算方法(其實就是樹上距離的求法),不禁讓我想著根據 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\n",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\n",fa[i+1]); return 0; }