HDU 4009 最小树形图

/********************************************************************************
    模板题。。。问题是比赛的时候一直没看出来,以为最小费用流,Racebug用邻接矩阵敲的,
结果杯具TLE,要是用邻接表再稍微优化下的,就过了~
********************************************************************************/
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <cstdio>
#include <memory>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef map<int, int>::iterator MI;
typedef vector<int>::iterator VI;
typedef set<int>::iterator SI;

const int INF_INT = 0x3f3f3f3f;
const double oo = 10e9;
const double eps = 10e-7;
const double PI = acos(-1.0);

const int MAXV = 1004;
const int MAXE = MAXV * MAXV;

struct Point
{
    int x, y, z;
}pnt[MAXV];
struct Edges
{
    int beg, end;
    int cost;
    int next;
}edges[MAXE];
int ecnt, head[MAXV];
int n, X, Y, Z;
int in[MAXV], pre[MAXV], id[MAXV], vis[MAXV];
const int src = 0;

inline int manhattan_dist(const Point &pa, const Point &pb)
{
    return abs(pa.x - pb.x) + abs(pa.y - pb.y) + abs(pa.z - pb.z);
}
inline void add_edge(int u, int v, int c)
{
    edges[ecnt].beg = u;
    edges[ecnt].end = v;
    edges[ecnt].cost = c;
    edges[ecnt].next = head[u];
    head[u] = ecnt++;
    return ;
}
int directed_mst(int root, int vcnt)
{
    int res = 0;
    while (true)
    {
        fill(in, in + vcnt, INF_INT);
        for (int i = 0; i < ecnt; ++i)
        {
            int u = edges[i].beg;
            int v = edges[i].end;
            if (edges[i].cost < in[v] && u != v)
            {
                pre[v] = u;
                in[v] = edges[i].cost;
            }
        }
        for (int i = 0; i < vcnt; ++i)
        {
            if (root == i)
            {
                continue ;
            }
            if (INF_INT == in[i])
            {
                return -1;
            }
        }
        int ncnt = 0;
        fill(id, id + vcnt, -1);
        fill(vis, vis + vcnt, -1);
        in[root] = 0;
        for (int i = 0; i < vcnt; ++i)
        {
            res += in[i];
            int v = i;
            while (vis[v] != i && -1 == id[v] && v != root)
            {
                vis[v] = i;
                v = pre[v];
            }
            if (v != root && -1 == id[v])
            {
                for (int u = pre[v]; u != v; u = pre[u])
                {
                    id[u] = ncnt;
                }
                id[v] = ncnt++;
            }
        }
        if (0 == ncnt)
        {
            break ;
        }
        for (int i = 0; i < vcnt; ++i)
        {
            if (-1 == id[i])
            {
                id[i] = ncnt++;
            }
        }
        for (int i = 0; i < ecnt; ++i)
        {
            int v = edges[i].end;
            edges[i].beg = id[ edges[i].beg ];
            edges[i].end = id[ edges[i].end ];
            if (edges[i].beg != edges[i].end)
            {
                edges[i].cost -= in[v];
            }
        }
        vcnt = ncnt;
        root = id[root];
    }
    return res;
}
void ace()
{
    int k, u, v;
    int ans, buf;
    while (scanf("%d %d %d %d", &n, &X, &Y, &Z), n || X || Y || Z)
    {
        ++n;
        ecnt = 0;
        memset(head, -1, sizeof(head));
        for (int i = 1; i < n; ++i)
        {
            scanf("%d %d %d", &pnt[i].x, &pnt[i].y, &pnt[i].z);
        }
        for (u = 1; u < n; ++u)
        {
            add_edge(src, u, pnt[u].z * X);
        }
        for (u = 1; u < n; ++u)
        {
            scanf("%d", &k);
            while (k--)
            {
                scanf("%d", &v);
                if (v == u)
                {
                    continue ;
                }
                buf = manhattan_dist(pnt[u], pnt[v]) * Y;
                if (pnt[u].z < pnt[v].z)
                {
                    buf += Z;
                }
                add_edge(u, v, buf); 
            }
        }
        ans = directed_mst(src, n);
        if (-1 == ans)
        {
            puts("poor XiaoA");
        }
        else
        {
            printf("%d\n", ans);
        }
    }
    return ;
}
int main()
{
    ace();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值