這道題是求最小生成樹的總權值,以及生成樹任意兩點之間距離的期望。求最小生成樹就直接用Kruskal算法生成就好了,求期望一開始用的是map發現會爆內存,後來改了之後還是超時了,方法不對,正解其實是用dfs來更新每個節點的兒子個數,然後由於數據範圍比較大,一定要記得開long long還有double,下面是原題和代碼:
Abandoned country
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2735 Accepted Submission(s): 672
For each test case, the first line contains two integers n,m indicate the number of villages and the number of roads to be re-built. Next m lines, each line have three number i,j,wi, the length of a road connecting the village i and the village j is wi.
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<stack>//最小生成樹、並查集、dfs
using namespace std;
typedef long long ll;
typedef struct Edge{
int fro, to;
int w;
}Edge;
Edge e[1000010];
vector< pair<int, int> >p[100010];//只存了最小生成樹數據結構的表
int pre[100010];//記錄每個節點的前驅
int son[100010];//記錄了每個節點的兒子個數
int wt[100010];//記錄了每個子節點點所擁有的邊的邊權
int vis[100010];
bool cmp(Edge a, Edge b)
{
return a.w < b.w;
}
int find(int i)
{
if(pre[i] == i)
return i;
else
return pre[i] = find(pre[i]);
}
void join(int x, int y)
{
int fx = find(x), fy = find(y);
if(fx != fy)
pre[fx] = fy;//這裏有問題啊。。。
}
int init(int k)//更新每個節點的兒子數
{
vis[k] = 1;
int ans = 0;
for(int i = 0; i < p[k].size(); i++)
{
if(!vis[p[k][i].first])
{
wt[p[k][i].first] = p[k][i].second;
ans += init(p[k][i].first);
}
}
return son[k] = (ans+1);
}
int main()
{
int t, num = 0;
//freopen("1001.in", "r", stdin);記得刪掉文件重定向啊!!!
//freopen("1001.txt","w", stdout);
scanf("%d", &t);
while(t--)
{
int n, m;
ll maxa = 0;
ll exp = 0;
scanf("%d%d", &n, &m);
memset(son, 0, sizeof(son));
memset(vis, 0, sizeof(vis));
memset(pre, 0, sizeof(pre));
memset(wt, 0, sizeof(wt));
for(int i= 1; i <= n; i++)
p[i].clear();
for(int i = 1; i <= m; i++)
scanf("%d%d%d", &e[i].fro, &e[i].to, &e[i].w);
if(n == 1)//特殊情況要判定
{
printf("0 0\n");
continue;
}
sort(e+1, e+m+1, cmp);
for(int i = 1; i <= n; i++)
pre[i] = i;
int rst = n, ans = 0;
for(int i = 1; i <= m && rst > 1; i++)
{
int x = e[i].fro, y = e[i].to;
int fx = find(x), fy = find(y);
if(fx == fy)
continue;
else
{
join(x, y);
rst--;
maxa += e[i].w;
p[x].push_back(make_pair(y, e[i].w));//只存節點的數據結構,只能存最小生成樹的結構,不要搞錯了!!
p[y].push_back(make_pair(x, e[i].w));
}
}
int t = find(1);//尋找整個生成樹的根
init(t);//給最小生成樹建樹,並更新每個節點的子節點個數
for(int i = 1; i <= n; i++)//統計總的邊權
{
//printf("son[%d]:%d %d\n", i, son[i], wt[i]);
if(i != t)
exp += ((ll)son[i]*(n-son[i])*wt[i]);//這裏要用ll不然會爆
}
double down = (double)n*(n-1)/2;
printf("%I64d %.2f\n", maxa, exp/(double)down);
//num++;
}
return 0;
}