zoukankan      html  css  js  c++  java
  • 最小树形图

    题目描述

    给定包含 n 个结点, m条有向边的一个图。试求一棵以结点 r 为根的最小树形图,并输出最小树形图每条边的权值之和,如果没有以 r 为根的最小树形图,输出 -1

    输入格式

    第一行包含三个整数 n,m,r,意义同题目所述。

    接下来 m 行,每行包含三个整数 u,v,w表示图中存在一条从 u 指向 v 的权值为 w的有向边。

    输出格式

    如果原图中存在以 rr 为根的最小树形图,就输出最小树形图每条边的权值之和,否则输出 -1

    输入输出样例

    输入
      
    4 6 1
    1 2 3
    1 3 1
    4 1 2
    4 2 2
    3 2 1
    3 4 1
    输出 #
    3
    输入 #2
    4 6 3
    1 2 3
    1 3 1
    4 1 2
    4 2 2
    3 2 1
    3 4 1
    输出 #2
    4
    输入 #3
    4 6 2
    1 2 3
    1 3 1
    4 1 2
    4 2 2
    3 2 1
    3 4 1
    输出 #3
    -1

    说明/提示

    样例 1 解释

    最小树形图中包含第 2, 5, 6 三条边,总权值为1+1+1=3

    样例 2 解释

    最小树形图中包含第 3, 5, 6 三条边,总权值为 2+1+1=3

    样例 3 解释

    无法构成最小树形图,故输出 -1 。

    #include <bits/stdc++.h>
    
    using namespace std;
    const int inf=2e9;
    const int maxn=10010;
    int n,m,root;
    int head[1000],in[1000],pre[1000],vis[1000],id[1000];
    long long ans;
    
    struct node{
        int from,to,val;
    }E[maxn];
    
    
    long long mintree()
    {
        while (1)
        {
            for (int i=1; i<=n; i++)
            {
                in[i]=inf;
            }
            for (int i=1; i<=m; i++)
            {
                if (E[i].from!=E[i].to&&E[i].val<in[E[i].to])
                {
                    in[E[i].to]=E[i].val;
                    pre[E[i].to]=E[i].from;
                }
            }
            for (int i=1; i<=n; i++)
            {
                if (in[i]==inf&&i!=root)
                {
                    return -1;
                }
            }
            int cnt=0;
            memset(vis,0,sizeof(vis));
            memset(id,0,sizeof(id));
            in[root]=0;
            for (int i=1; i<=n; i++)
            {
                ans+=in[i];
                int v=i;
                while (vis[v]!=i&&id[v]==0&&v!=root)
                {
                    vis[v]=i;
                    v=pre[v];
                }
                //找环
                if (v!=root&&id[v]==0)
                {
                    id[v]=++cnt;
                    for (int u=pre[v]; u!=v; u=pre[u])
                    {
                        id[u]=cnt;
                    }
                }
                //对环进行收缩
            }
            if (!cnt)
            {
                break;
            }
            for (int i=1;i<=n;i++){
                if (!id[i]){
                    id[i]=++cnt;
                }
            }
            for (int i=1;i<=m;i++){
                int u=E[i].from,v=E[i].to;
                E[i].from=id[E[i].from];
                E[i].to=id[E[i].to];
                if (u!=v){
                    E[i].val-=in[v];
                }
            }//新建图
            n=cnt;
            root=id[root];
        }
        return ans;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&root);
        for (int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&E[i].from,&E[i].to,&E[i].val);
        }
        printf("%lld
    ",mintree());
    }
    

      

  • 相关阅读:
    !!!最常用正则表达式语法
    RunMessageScript from spy
    已知进程、线程、窗体三者中某一个的句柄,需要查找另外两者的句柄。
    如何抓取一个当前运行软件所使用的内存
    谢谢你的伤害
    游摸底河有感
    九月无诗
    游石人公园有感
    影响35岁前成功的好习惯与坏习惯
    创业经验十二谈,愿有志者共勉(转)
  • 原文地址:https://www.cnblogs.com/Accpted/p/11349264.html
Copyright © 2011-2022 走看看