P4716 模板最小树形图

Posted popo-black-cat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4716 模板最小树形图相关的知识,希望对你有一定的参考价值。

  一道模版题(就是这个算法有点偏……)

  这道题就是在一个有向图中,求出一个定根的有根树,使其边权之和最小,其实就是有向图的最小生成树。

  其实挺简单的……没我想象的那么高深。就是在改边权的地方有点不好理解,正确性可以用数学归纳法证明。

  一次次缩点直到这个图不再有环为止。

  代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<climits>
using namespace std;
#define maxn 20000
#define inf 999999999
struct node
{
    int from,to,w;
} edge[maxn];
int in[maxn],pre[maxn],id[maxn];
int vis[maxn];
int n,m,root,cnt;
void add(int a,int b,int w)
{
    edge[++cnt].to=b;
    edge[cnt].from=a;
    edge[cnt].w=w;
}
int zhuliu()
{
    int ans=0;
    while(1)
    {
        for(int i=1; i<=n; i++)
            in[i]=inf;
        for(int i=1; i<=m; i++)
        {
            int u=edge[i].from;
            int v=edge[i].to;
            if(u!=v&&edge[i].w<in[v])
            {
                in[v]=edge[i].w;
                pre[v]=u;
            }
        }
        for(int i=1; i<=n; i++)
            if(i!=root&&in[i]==inf) return -1;
        int num=0;
        memset(vis,0,sizeof(vis));
        memset(id,0,sizeof(id));
        for(int i=1;i<=n;i++)
        {
            if(i==root) continue;
            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]=++num;
                for(int j=pre[v];j!=v;j=pre[j])
                    id[j]=num;
            } 
        }
        if(!num) break;
        for(int i=1;i<=n;i++)
            if(!id[i]) id[i]=++num;
        for(int i=1;i<=m;i++)
        {
            int u=edge[i].from;
            int v=edge[i].to;
            edge[i].from=id[u];
            edge[i].to=id[v];
            if(id[u]!=id[v]) edge[i].w-=in[v];
        }
        root=id[root];
        n=num;
    }
    return ans;
}
int main()
{
    scanf("%d%d%d",&n,&m,&root);
    for(int i=1; i<=m; i++)
    {
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        add(a,b,w);
    }
    printf("%d\n",zhuliu());
    return 0;
}

 

以上是关于P4716 模板最小树形图的主要内容,如果未能解决你的问题,请参考以下文章

最小树形图(模板)

poj3164最小树形图模板题

最小树形图模板 UVA11183

POJ 3164 Command Network(最小树形图模板题+详解)

uva11183最小树形图

最小树形图