Transfer water - HDU 4009 - 最小树形图

本文介绍了一种解决三维空间中最小树形图问题的算法实现,通过具体实例讲解了如何利用C++编程语言构建图结构并求解。文章详细记录了从理解题目要求到实现算法模板的全过程,包括调试过程中遇到的问题及解决方法。

题目

  http://acm.hdu.edu.cn/showproblem.php?pid=4009

题意

  给定n个点的三维坐标,以及根节点到每个点的单向权值,再给定n个节点间相互单向连接的成本,求最小树形图。

思路

  直接根据题意建图然后跑最小树形图模板,网上有人说这个题必定有解我觉得说法是错的,因为有些时候两点之间未必可以链接。

过程

  因为对模板不是很熟WA了很多发也DeBug了很久,发现是找完环之后忘了标记整个环,具体表现是80到83行之间的代码忘了写,所以一直在错。再就是发现定义虚根的先后次序不影响最后的结果,以及在网上寻找模板进行对比的时候发现了fill()这个函数。

fill(a,b,c);

等价于

for(int i=0 ; i<b ; i++) a[i] = c;

代码

//
//  main.cpp
//  L
//
//  Created by LucienShui on 2017/7/15.
//  Copyright © 2017年 LucienShui. All rights reserved.
//

#include <iostream>
#include <algorithm>
#include <set>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#define il inline
#define ll long long
#define memset(a,b) memset(a,b,sizeof(a))

using namespace std;

#define maxn 1007

struct {
    int x, y, z;
}point[maxn];

struct {
    int u, v;
    ll w;
}edge[maxn*maxn];

ll in[maxn];
int pre[maxn], id[maxn], vis[maxn];
const int INF = 0x3f3f3f3f;

int dis(int a, int b) {
    int x = abs(point[a].x - point[b].x), y = abs(point[a].y - point[b].y),
    z = abs(point[a].z - point[b].z);
    return x + y + z;
}

ll directed_MST(int root, int n, int m) {
    ll ans = 0;
    while(true) {
        fill(in, in+n, INF);//for(int i=0 ; i<n ; i++) in[i] = INF;
        for(int i=0 ; i<m ; i++) {
            int u = edge[i].u, v = edge[i].v;
            if(edge[i].w < in[v] && u!=v) {
                in[v] = edge[i].w;
                pre[v] = u;
            }
        }
        for(int i=0 ; i<n ; i++)
            if(in[i] == INF && i != root)
                return -1;
        int cnt = 0;
        memset(id, -1);
        memset(vis, -1);
        in[root] = 0;
        for(int i=0 ; i<n ; i++) {
            ans += in[i];
            int v = i;
            while(vis[v] != i && id[v] == -1 && v != root) {
                vis[v] = i;
                v = pre[v];
            }
            if(v != root && id[v] == -1) {
                for(int u = pre[v] ; u != v ; u = pre[u]) id[u] = cnt;
                id[v] = cnt++;
            }
        }
        if(cnt == 0) break;
        /*line 80*/
        for(int i=0 ; i<n ; i++)
            if(id[i] == -1) id[i] = cnt++;
        /*line 83*/
        for(int i=0 ; i<m ; i++) {
            int u = edge[i].u, v = edge[i].v;
            edge[i].u = id[u];
            edge[i].v = id[v];
            if(id[u] != id[v]) {
                edge[i].w -= in[v];
            }
        }
        n = cnt;
        root = id[root];
    }
    return ans;
}

int main (int argc, char* argv[]) {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    int n, m, tmp, v, X, Y, Z;
    while(scanf("%d%d%d%d", &n, &X, &Y, &Z), (n || X || Y || Z)) {
        m = 0;
        for(int i=1 ; i<=n ; i++) {
            scanf("%d%d%d", &point[i].x, &point[i].y, &point[i].z);
            edge[m].u = 0;
            edge[m].v = i;
            edge[m++].w = X * point[i].z;
        }
        for(int u=1 ; u<=n ; u++) {
            scanf("%d",&tmp);
            while(tmp--) {
                scanf("%d",&v);
                if(u == v) continue;
                edge[m].u = u;
                edge[m].v = v;
                edge[m].w = Y * dis(u,v);
                if(point[u].z < point[v].z) {
                    edge[m].w += Z;
                }
                m++;
            }
        }
        ll ans = directed_MST(0,n+1,m);
        if(ans == -1) puts("poor XiaoA");
        else printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值