poj 3164(最小树形图模板)

题目链接:http://poj.org/problem?id=3164

详细可以看这里:http://www.cnblogs.com/vongang/archive/2012/07/18/2596851.html

我没怎么看懂 = =,姑且做个模板了。。

题意就是给n个点,m条单向边,并且已知根节点,求有向图的最小生成树。

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
typedef double type;
const int N = 105;
const int M = 10005;
const type INF = 999999999;
struct Point
{
    int x,y;
} p[N];
struct Edge
{
    int u,v;
    double cost;
} edge[M];
///最小树形图算法
type IN[N];
int vis[N],pre[N],id[N];
type Directed_MST(int root,int n,int m)  ///n为点数,m为边数
{
    type cost = 0;
    while(true)
    {
        ///找最小入边
        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].cost<IN[v]&&u!=v)
            {
                pre[v]=u,IN[v]=edge[i].cost;
            }
        }
        for(int i=0; i<n; i++) ///判断是否有最小树形图(除了root之外还存在点没有入边)
        {
            if(i==root) continue;
            if(IN[i]==INF) return -1;
        }
        ///找环
        int cnt = 0; ///环的计数器
        memset(id,-1,sizeof(id));
        memset(vis,-1,sizeof(vis));
        IN[root] = 0;
        for(int i=0; i<n; i++)
        {
            cost +=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; ///无环了
        for(int i=0; i<n; i++)
        {
            if(id[i]==-1) id[i]=cnt++;
        }
        ///建立新图
        for(int i = 0; i < m; i++)
        {
            int u = edge[i].u;
            int v = edge[i].v;
            edge[i].u = id[u];
            edge[i].v = id[v];
            if(id[u] != id[v]) edge[i].cost -= IN[v];
        }
        n = cnt;
        root = id[root];
    }
    return cost;
}
double dis(Point a,Point b)
{
    return sqrt(1.0*((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0; i<n; i++)
        {
            scanf("%d%d",&p[i].x,&p[i].y);
        }
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&edge[i].u,&edge[i].v);
            edge[i].u--,edge[i].v--;
            if(edge[i].u==edge[i].v) edge[i].cost = INF; ///除去自环
            else edge[i].cost = dis(p[edge[i].u],p[edge[i].v]);
        }
        double cost = Directed_MST(0,n,m);
        if(cost==-1) printf("poor snoopy
");
        else printf("%.2lf
",cost);
    }
}
原文地址:https://www.cnblogs.com/liyinggang/p/5474221.html