【最小树形图】最小树形图复习

模板题:

poj3164 Command Network

/***********************************\
 * @prob: poj3164 Command Network  *
 * @auth: Wang Junji               *
 * @stat: Accepted.                *
 * @date: June. 25th, 2012         *
 * @memo: 最小树形图                *
\***********************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>

const int maxN = 110;
const double INF = 1e198;

double mp[maxN][maxN], x[maxN], y[maxN];
bool del[maxN];
int pre[maxN], root, n, m;

template <typename _Tp>
inline _Tp& gmax(_Tp& a, const _Tp& b)
{return a > b ? a : (a = b);}
/* gmax */

template <typename _Tp>
inline _Tp& gmin(_Tp& a, const _Tp& b)
{return a < b ? a : (a = b);}
/* gmin */

template <typename _Tp>
inline _Tp sqr(const _Tp& x) {return x * x;} /* sqr */

inline bool connected()
{
    static const int SIZE = 0x3ffff;
    static int q[SIZE + 1];
    static bool marked[maxN];
    memset(marked, 0, sizeof marked);
    int f = 0, r = 0, u, v;
    for (q[r++] = 0; f - r;)
    for (marked[u = q[f++]] = true, f &= SIZE, v = 0; v < n; ++v)
        if (mp[u][v] < INF && !marked[v]) marked[q[r++] = v] = true, r &= SIZE;
    for (int i = 0; i < n; ++i)
        if (!marked[i]) return false;
    return true;
} /* connected */

inline int loop()
{
    pre[root = 0] = 0;
    for (int i = 0; i < n; ++i)
    if (!del[i] && i != root)
    {
        mp[i][i] = INF; pre[i] = i;
        for (int j = 0; j < n; ++j)
        if (!del[j] && mp[j][i] < mp[pre[i]][i])
            pre[i] = j;
    } /* if */
    for (int i = 0; i < n; ++i) if (!del[i] && i != root)
    {
        static bool vis[maxN];
        memset(vis, 0, sizeof vis);
        int j = i;
        for (; !vis[j]; j = pre[j]) vis[j] = true;
        if (j == root) continue;
        else return j;
    } /* if */
    return -1;
} /* loop */

inline void update(int t, double& ans)
{
    ans += mp[pre[t]][t];
    for (int i = pre[t]; i != t; i = pre[i])
        ans += mp[pre[i]][i], del[i] = true;
    for (int i = 0; i < n; ++i)
    if (!del[i] && mp[i][t] < INF)
        mp[i][t] -= mp[pre[t]][t];
    for (int j = pre[t]; j != t; j = pre[j])
    for (int i = 0; i < n; ++i)
    if (!del[i])
    {
        if (mp[i][j] < INF)
            gmin(mp[i][t], mp[i][j] - mp[pre[j]][j]);
        if (mp[j][i] < INF) gmin(mp[t][i], mp[j][i]);
    } /* for */
    return;
} /* update */

inline double solve()
{
    memset(del, 0, sizeof del);
    double ans = 0; int j;
    while (~(j = loop())) update(j, ans);
    for (int i = 0; i < n; ++i)
    if (!del[i] && i != root)
        ans += mp[pre[i]][i];
    return ans;
} /* solve */

int main()
{
    freopen("network.in" , "r", stdin );
    freopen("network.out", "w", stdout);
    while (~scanf("%d%d", &n, &m))
    {
        for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            mp[i][j] = INF;
        for (int i = 0; i < n; ++i)
            scanf("%lf%lf", x + i, y + i);
        while (m--)
        {
            int u, v; scanf("%d%d", &u, &v); --u, --v;
            mp[u][v] = sqrt(sqr(x[u] - x[v]) + sqr(y[u] - y[v]));
        } /* while */
        if (!connected()) puts("poor snoopy");
        else printf("%.2lf\n", solve());
    } /* while */
    return 0;
} /* main */

/*

最小树形图模板题,不多说。

*/

tju2248 Channel Design

/**********************************\
 * @prob: tju2248 Channel Design  *
 * @auth: Wang Junji              *
 * @stat: Accepted.               *
 * @date: June. 25th, 2012        *
 * @memo: 最小树形图                *
\**********************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 110, maxM = 10010, INF = 0x3f3f3f3f;

struct Edge
{
    int u, v, d;
    Edge(int u = 0, int v = 0, int d = 0): u(u), v(v), d(d) {} /* Edge */
} edge[maxM];
int n, m;

int Directed_MST(int root, int n, int m)
{
    int res = 0;
    for (;;)
    {
        static int In[maxN], pre[maxN], ID[maxN], vis[maxN];
        memset(In, 0x3f, sizeof In);
        for (int j = 0; j < m; ++j)
        {
            int u = edge[j].u, v = edge[j].v, d = edge[j].d;
            if (u != v && d < In[v]) In[v] = d, pre[v] = u;
        } /* for */
        for (int i = 0; i < n; ++i)
        if (i != root && In[i] == INF)
            return -1;
        memset(vis, 0xff, sizeof vis);
        memset(ID , 0xff, sizeof ID );
        int cnt_v = 0;
        for (int i = 0; i < n; ++i) if (i != root)
        {
            res += In[i]; int u = i;
            for (; vis[u] != i && ID[u] == -1 && u != root; u = pre[u])
                vis[u] = i;
            if (u != root && ID[u] == -1)
            {
                for (int v = pre[u]; v != u; v = pre[v])
                    ID[v] = cnt_v;
                ID[u] = cnt_v++;
            } /* if */
        } /* if */
        if (!cnt_v) break;
        for (int i = 0; i < n; ++i) if (ID[i] == -1) ID[i] = cnt_v++;
        for (int j = 0; j < m; ++j)
        {
            int v = edge[j].v;
            edge[j].u = ID[edge[j].u];
            edge[j].v = ID[edge[j].v];
            if (edge[j].u != edge[j].v)
                edge[j].d -= In[v];
        } /* for */
        n = cnt_v;
        root = ID[root];
    } /* for */
    return res;
} /* Directed_MST */

int main()
{
    freopen("design.in" , "r", stdin );
    freopen("design.out", "w", stdout);
    while (~scanf("%d%d", &n, &m) && (n || m))
    {
        int cnt_e = 0;
        while (m--)
        {
            int u, v, d; scanf("%d%d%d", &u, &v, &d);
            edge[cnt_e++] = Edge(--u, --v, d);
        } /* while */
        int ans = Directed_MST(0, n, cnt_e);
        if (ans < 0) puts("impossible");
        else printf("%d\n", ans);
    } /* while */
    return 0;
} /* main */

/*

最小树形图模板题,不多说。

*/

UVa11183 Teen Girl Squad

/************************************\
 * @prob: UVa11183 Teen Girl Squad  *
 * @auth: Wang Junji                *
 * @stat: Accepted.                 *
 * @date: June. 25th, 2012          *
 * @memo: 最小树形图                 *
\************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 1010, maxM = 40010, INF = 0x3f3f3f3f;
struct Edge {int u, v, d;} edge[maxM];
int n, m, T;

int Directed_MST(int root, int n, int m)
{
    int res = 0;
    for (;;)
    {
        static int In[maxN], pre[maxN], ID[maxN], vis[maxN];
        memset(In, 0x3f, sizeof In);
        for (int j = 0; j < m; ++j)
        {
            int u = edge[j].u, v = edge[j].v, d = edge[j].d;
            if (u != v && d < In[v]) In[v] = d, pre[v] = u;
        } /* for */
        for (int i = 0; i < n; ++i)
        if (i != root && In[i] == INF)
            return -1;
        memset(ID , 0xff, sizeof ID );
        memset(vis, 0xff, sizeof vis);
        int cnt_v = 0;
        for (int i = 0; i < n; ++i) if (i != root)
        {
            res += In[i]; int u = i;
            for (; vis[u] != i && ID[u] == -1 && u != root; u = pre[u])
                vis[u] = i;
            if (ID[u] == -1 && u != root)
            {
                for (int v = pre[u]; v != u; v = pre[v])
                    ID[v] = cnt_v;
                ID[u] = cnt_v++;
            } /* if */
        } /* if */
        if (!cnt_v) break;
        for (int i = 0; i < n; ++i) if (ID[i] == -1) ID[i] = cnt_v++;
        for (int j = 0; j < m; ++j)
        {
            int v = edge[j].v;
            if ((edge[j].u = ID[edge[j].u]) != (edge[j].v = ID[edge[j].v]))
                edge[j].d -= In[v];
        } /* for */
        root = ID[root];
        n = cnt_v;
    } /* for */
    return res;
} /* Directed_MST */

int main()
{
    freopen("girl.in" , "r", stdin );
    freopen("girl.out", "w", stdout);
    for (scanf("%d", &T); T--;)
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; ++i)
            scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].d);
        static int Case = 0;
        printf("Case #%d: ", ++Case);
        int ans = Directed_MST(0, n, m);
        if (ans < 0) puts("Possums!");
        else printf("%d\n", ans);
    } /* for */
    return 0;
} /* main */

/*

最小树形图模板题,不多说。

*/
无定根:

hdu2121 Ice_cream’s world II

/****************************************\
 * @prob: hdu2121 Ice_cream’s world II  *
 * @auth: Wang Junji                    *
 * @stat: Accepted.                     *
 * @date: June. 25th, 2012              *
 * @memo: 最小树形图                     *
\****************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 1010, maxM = 11010;
typedef long long int64;
int64 INF = 0x3f3f3f3f3f3f3f3fLL;
struct Edge {int u, v; int64 d;} edge[maxM];
int n, m;

int64 Directed_MST(int root, int n, int m, int& root_id)
{
    int64 res = 0;
    for (;;)
    {
        static int pre[maxN], ID[maxN], vis[maxN];
        static int64 In[maxN];
        memset(In, 0x3f, sizeof In);
        for (int j = 0; j < m; ++j)
        {
            int u = edge[j].u, v = edge[j].v;
            int64 d = edge[j].d;
            if (u != v && d < In[v]) //!!
            {
                In[v] = d, pre[v] = u;
                if (u == root) root_id = j;
            } /* if */
        } /* for */
        for (int i = 0; i < n; ++i)
        if (i != root && In[i] == INF)
            return -1;
        memset(ID , 0xff, sizeof ID );
        memset(vis, 0xff, sizeof vis);
        int cnt_v = 0;
        for (int i = 0; i < n; ++i) if (i != root)
        {
            res += In[i]; int u = i;
            for (; vis[u] != i && ID[u] == -1 && u != root; u = pre[u])
                vis[u] = i;
            if (ID[u] == -1 && u != root)
            {
                for (int v = pre[u]; v != u; v = pre[v])
                    ID[v] = cnt_v;
                ID[u] = cnt_v++;
            } /* if */
        } /* if */
        if (!cnt_v) break;
        for (int i = 0; i < n; ++i) if (ID[i] == -1) ID[i] = cnt_v++;
        for (int j = 0; j < m; ++j)
        {
            int v = edge[j].v;
            if ((edge[j].u = ID[edge[j].u]) != (edge[j].v = ID[edge[j].v]))
                edge[j].d -= In[v];
        } /* for */
        root = ID[root]; n = cnt_v;
    } /* for */
    return res;
} /* Directed_MST */

int main()
{
    freopen("Ice_cream.in" , "r", stdin );
    freopen("Ice_cream.out", "w", stdout);
    while (~scanf("%d%d", &n, &m))
    {
        int64 sum_d = 0;
        for (int i = 0; i < m; ++i)
            scanf("%d%d%lld", &edge[i].u, &edge[i].v, &edge[i].d), sum_d += edge[i].d;
        ++sum_d;
        int cnt_e = m, root_id = 0;
        for (int i = 0; i < n; ++i)
            edge[cnt_e].u = n, edge[cnt_e].v = i, edge[cnt_e++].d = sum_d;
        int64 ans = Directed_MST(n, n + 1, cnt_e, root_id) - sum_d;
        if (ans < 0 || ans >= sum_d) puts("impossible\n");
        else printf("%lld %d\n\n", ans, root_id - m);
    } /* while */
    return 0;
} /* main */

/*

无定根的最小树形图。
只需要加一个虚拟根,到所有点的权值恰好比所有原边权值之和略大(这样保证虚拟根只会与其中一个点连边),并且再记录一下根的位置就可以了(如果一个点的入边为虚拟根,那么这个点为“真实的”根)。

要用long long类型。


*/
(这并不是一道真正意义上的最小树形图:)

hdu3072 Intelligence System

/***************************************\
 * @prob: hdu3072 Intelligence System  *
 * @auth: Wang Junji                   *
 * @stat: Accepted.                    *
 * @date: June. 25th, 2012             *
 * @memo: 强连通分量                    *
\***************************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

typedef long long int64;
const int maxN = 50010, maxM = 100010;
const int64 INF = 0x3f3f3f3f3f3f3f3fLL;

struct Edge
{
    int u, v; int64 d; Edge* next; Edge() {} /* Edge */
    Edge(int u, int v, int64 d, Edge* next):
        u(u), v(v), d(d), next(next) {}
    /* Edge */
} __edge[maxM], *edge[maxN], *tot = __edge; 
bool marked[maxN];
int Low[maxN], DFN[maxN], sta[maxN];
int ID[maxN], n, m, Bcnt, Index, top;

template <typename _Tp>
inline _Tp& gmax(_Tp& a, const _Tp& b)
{return a > b ? a : (a = b);}
/* gmax */

template <typename _Tp>
inline _Tp& gmin(_Tp& a, const _Tp& b)
{return a < b ? a : (a = b);}
/* gmin */

void Tarjan(int u)
{
    DFN[u] = Low[u] = Index++;
    marked[sta[top++] = u] = true;
    for (Edge* p = edge[u]; p; p = p -> next)
    {
        if (DFN[p -> v] == -1) Tarjan(p -> v), gmin(Low[u], Low[p -> v]);
        else if (marked[p -> v])               gmin(Low[u], DFN[p -> v]);
    } /* for */
    if (Low[u] == DFN[u])
    {
        int tmp = u;
        do
            ID[tmp = sta[--top]] = Bcnt, marked[tmp] = false;
        while (tmp != u);
        ++Bcnt;
    } /* if */
    return;
} /* Tarjan */

int main()
{
    freopen("Intelligence.in" , "r", stdin );
    freopen("Intelligence.out", "w", stdout);
    while (~scanf("%d%d", &n, &m))
    {
        memset(edge, 0, sizeof edge); tot = __edge;
        while (m--)
        {
            int u, v; int64 d;
            scanf("%d%d%lld", &u, &v, &d);
            edge[u] = new (tot++) Edge(u, v, d, edge[u]);
        } /* while */
        memset(ID    , 0xff, sizeof ID    );
        memset(DFN   , 0xff, sizeof DFN   );
        memset(Low   , 0xff, sizeof Low   );
        memset(marked, 0   , sizeof marked);
        Bcnt = top = Index = 0;
        Tarjan(0);
        static int64 In[maxN];
        memset(In, 0x3f, sizeof In);
        for (Edge* p = __edge; p != tot; ++p)
        if (ID[p -> u] != ID[p -> v])
            gmin(In[ID[p -> v]], p -> d);
        In[ID[0]] = 0;
        int64 ans = 0;
        for (int i = 0; i < Bcnt; ++i) ans += In[i];
        printf("%lld\n", ans);
    } /* while */
    return 0;
} /* main */

/*

缩点,然后将所有最小入边相加。

*/

稍加变形:

hdu4009 Transfer water

/**********************************\
 * @prob: hdu4009 Transfer water  *
 * @auth: Wang Junji              *
 * @stat: Accepted.               *
 * @date: June. 25th, 2012        *
 * @memo: 最小树形图               *
\**********************************/
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>

const int maxN = 1010, maxM = maxN * (maxN + 1), INF = 0x3f3f3f3f;

struct Edge {int u, v, d;} edge[maxM];
int x[maxN], y[maxN], z[maxN], n, m, X, Y, Z, cnt_e;

inline int dist(int i, int j)
{return std::abs(x[i] - x[j]) + std::abs(y[i] - y[j]) + std::abs(z[i] - z[j]);}

inline void Ins(int u, int v, int d)
{
    edge[cnt_e].u = u;
    edge[cnt_e].v = v;
    edge[cnt_e].d = d;
    ++cnt_e; return;
} /* Ins */

int Directed_MST(int root, int n, int m)
{
    int res = 0;
    for (;;)
    {
        static int pre[maxN], ID[maxN], vis[maxN];
        static int In[maxN];
        memset(In, 0x3f, sizeof In);
        for (int j = 0; j < m; ++j)
        {
            int u = edge[j].u, v = edge[j].v;
            int d = edge[j].d;
            if (u != v && d < In[v]) In[v] = d, pre[v] = u;
        } /* for */
        for (int i = 0; i < n; ++i)
        if (i != root && In[i] == INF)
            return -1;
        memset(ID , 0xff, sizeof ID );
        memset(vis, 0xff, sizeof vis);
        int cnt_v = 0;
        for (int i = 0; i < n; ++i) if (i != root)
        {
            res += In[i]; int u = i;
            for (; ID[u] == -1 && u != root && vis[u] != i; u = pre[u])
                vis[u] = i;
            if (u != root && ID[u] == -1) //!!
            {
                for (int v = pre[u]; v != u; v = pre[v])
                    ID[v] = cnt_v;
                ID[u] = cnt_v++;
            } /* if */
        } /* if */
        if (!cnt_v) break;
        for (int i = 0; i < n; ++i) if (ID[i] == -1) ID[i] = cnt_v++; //!!
        for (int j = 0; j < m; ++j)
        {
            int v = edge[j].v;
            if ((edge[j].u = ID[edge[j].u]) != (edge[j].v = ID[edge[j].v]))
                edge[j].d -= In[v];
        } /* for */
        n = cnt_v;
        root = ID[root];
    } /* for */
    return res;
} /* Directed_MST */

int main()
{
    freopen("Transfer.in" , "r", stdin );
    freopen("Transfer.out", "w", stdout);
    while (~scanf("%d%d%d%d", &n, &X, &Y, &Z) && (n || X || Y || Z))
    {
        for (int i = 0; i < n; ++i)
            scanf("%d%d%d", x + i, y + i, z + i);
        cnt_e = 0;
        for (int i = 0, K, j; i < n; ++i)
        {
            scanf("%d", &K);
            while (K--)
            {
                scanf("%d", &j); --j;
                Ins(i, j, Y * dist(i, j) + (z[i] < z[j] ? Z : 0));
            } /* while */
        } /* for */
        for (int i = 0; i < n; ++i) Ins(n, i, z[i] * X);
        int ans = Directed_MST(n, n + 1, cnt_e);
        if (ans < 0) puts("poor XiaoA");
        else printf("%d\n", ans);
    } /* while */
    return 0;
} /* main */

/*

新建虚拟根,虚拟根到每个点的权值为该点自建水库的费用。
注意当i的海拔低于j时,仍然要算上Y的基本费用(Z为附加费用,而不是全部费用)。

*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值