1. 程式人生 > >HDU 5723 Abandoned country

HDU 5723 Abandoned country

#include "bits/stdc++.h"
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define fori(i,l,u) for(int i = l;i < u;i++)
#define forj(j,l,u) for(int j = l;j < u;j++)
#define F first
#define S second
#define pb push_back
#define mk make_pair
typedef long long  ll;
typedef pair<int, int> pi;
typedef pair<string, int> ps;
typedef vector<int> vi;
typedef vector<string> vs;
typedef vector<pi> vpi;
const int maxn = 1e5 + 6;
int t;
ll n,m;    //n是村莊,m是道路
ll ans;     //最小生成樹的權值
ll node[maxn],rk[maxn];
ll sum[maxn],dp[maxn];
typedef struct {
    ll u;
    ll v;
    ll w;
}road;
road R[maxn * 10];
typedef struct {
    ll v;
    ll w;
}N;
vector<N> tree[maxn];
void init(){        //初始化
    ans = 0;
    mem(sum,0);
    mem(dp,0);
    fori(i, 1, n+1){
        node[i] = i;
        rk[i] = 0;
        tree[i].clear();
    }
}
ll find(ll x){
    if (x == node[x]) {
        return x;
    }
    return node[x] = find(node[x]);
}
void merge(ll x,ll y){
    x = find(x);
    y = find(y);
    if (rk[x] < rk[y]) {
        node[x] = y;
    }
    else{
        node[y] = x;
        if (rk[x] == rk[y]) {
            rk[x] ++;
        }
    }
}
bool compare(const road& x,const road &y){
    return x.w < y.w;
}
void Kruskal(ll m){
    int num = 0;
    for(int i = 0;i < m && num != n-1 ;i++){
        if (find(R[i].u) != find(R[i].v)) {
            num ++;
            ans += R[i].w;
            merge(R[i].u,R[i].v);
            // 新增最小生成樹
            N t1,t2;
            t1.v = R[i].u; t1.w = R[i].w;
            t2.v = R[i].v; t2.w = R[i].w;
            tree[R[i].v].pb(t1);
            tree[R[i].u].pb(t2);
        }
    }
}
void dfs(ll cur,ll ft){
    sum[cur] = 1;
    fori(i, 0, tree[cur].size()){
        ll son = tree[cur][i].v;
        ll len = tree[cur][i].w;
        if (ft == son) {        //至關重要
            continue;
        }
        dfs(son, cur);
        sum[cur] += sum[son];
        dp[cur] += dp[son] + (n-sum[son])*sum[son]*len;
    }
}
int main()
{
//    freopen("1.txt", "r", stdin);
    scanf("%d",&t);
    while (t--) {
        scanf("%lld%lld",&n,&m);
        init();
        fori(i, 0, m){      //道路的標號從0開始
            scanf("%lld%lld%lld",&R[i].u,&R[i].v,&R[i].w);
        }
        sort(R, R+m,compare);

        Kruskal(m);
        ll cur = 0;
        fori(i, 1, n+1){
            if (node[i] == i) {
                cur = i;
                break;
            }
        }
        dfs(cur, -1);
        double num = n*(n-1)/2;
        cout<<ans<<" ";
        printf("%.2lf\n",(double)dp[cur]/num);
    }
    return 0;
}


此程式碼和上述兩題的結構一樣,基本上是抄板子的。

  • 遇到的問題 : 說的輕鬆,遇到的問題真是。。心酸 1)注意n和m的範圍,一個是10w,一個是100w,設定maxn = 1e5 + 6,然後邊的結構體陣列的範圍是 10 * maxn。 2)int會wa。。雖然不知道為什麼,有一道最小生成樹還是樹形dp的題也是這樣,不過都改成ll肯定沒錯。。 3)cin會wa,這兩種型別的題,最小生成樹,樹形dp,一般都用scanf,有的題會有hint : scanf recommend 4)dfs和Kruskal注意邊界問題。