hdu_5723_Abandoned country(最小生成樹)

題目鏈接:hdu_5723_Abandoned country

題意:

讓你求最小生成樹的花費,然後求任給兩點的期望路程

題解:

最小生成樹大家都會求,Kruskal這裏要改改,因爲後面要求任意兩點的期望路程,我們這裏Kruskal 記錄下最小生成樹的邊,然後通過DFS把樹建出來,最後找每條邊經過了多少次,然後乘上對應的組合,比如樣列,第一條邊權爲1的邊,這條邊左邊只有一個節點,右邊有3個節點,那麼這條邊就會經過3次,所以這條邊的貢獻就是1(左邊點個數)*3(右邊點個數)*1(邊權),依次類推,然後最後總和除以(n*(n-1)/2),因爲任意點對有這麼多種組合的方式,這裏的數據居然沒有設計成最後除會爆double的,所以不用邊除邊加,當然保險的是邊除邊加

#include<cstdio>
#include<algorithm>
#define F(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int N=1e5+7,M=1e6+7;
int n,m,g[N],nxt[N*2],v[N*2],ed,f[N],a[N],sz[N];

inline void adg(int x,int y){v[++ed]=y,nxt[ed]=g[x],g[x]=ed;}

struct edge{
	int u,v,w;
	bool operator<(const edge &b)const{return w<b.w;}
}e[M];

inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}

void Kruskal(int tot=0){
	sort(e+1,e+1+m);
	F(i,1,n)f[i]=i;
	F(i,1,m){
		int fu=find(e[i].u),fv=find(e[i].v);
		if(fu!=fv)a[++tot]=i,f[fu]=fv;
		if(tot==n-1)break;
	}
}

void dfs(int x,int pre){
	sz[x]=1;
	for(int i=g[x];i;i=nxt[i])
		if(v[i]!=pre)dfs(v[i],x),sz[x]+=sz[v[i]];
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		F(i,1,m)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
		Kruskal();
		F(i,1,n)g[i]=0;ed=0;
		F(i,1,n-1){
			adg(e[a[i]].u,e[a[i]].v);
			adg(e[a[i]].v,e[a[i]].u);
		}
		dfs(1,1);
		double ans=0,div=(1.0*n*(n-1)/2);
		long long an=0;
		F(i,1,n-1){
			int u=e[a[i]].u,v=e[a[i]].v;
			if(sz[u]<sz[v])u^=v,v^=u,u^=v;
			an+=e[a[i]].w;
			ans+=(double)(sz[v])*(n-sz[v])*e[a[i]].w;
		}
		printf("%lld %.2lf\n",an,ans/div);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章