【POJ3164】Command Network 最小树形图模板题 重修版

链接:

#include 
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44935891");
}

我以前的版本

算法构造过程以及傻叉代码+弱版注释见以前博客
http://blog.csdn.net/vmurder/article/details/38819711

最小树形图:

名词解释:

        其实就是有向图的最小生成树,然后需要有一个根(一般默认为1),如果是无根最小树形图,我们可以牺牲时间复杂度, O(n) 枚举根跑最小树形图。

算法流程:

  1. 对于一张有向图,除了根以外每个点都找一条权值最小的入边(称之为 [最小弧] )
  2. 这样就可能构成了一片由基环树组成的森林,然后我们把每个环都缩点,并根据点的新编号重建图。但是如果没有环(所有点与根连通),则最小树形图已经建成,跳出流程。

如果计算边权:

每次将所有点(根除外)最小弧长度累加,重建图时与x相连的边权值全部减去此最小弧长度,这样就保证了最后一个点的流程中加得的所有最小弧长度等于最后一次加的边的原长度。

代码:

#include 
#include 
#include 
#include 
#include 
#define inf 0x3f3f3f3f
#define N 200
#define M 50000
using namespace std;
struct Fiona
{
    double x,y;
}s[N];
struct Syndra
{
    int u,v;
    double w;
}e[M];
int pre[N],f[N],vis[N];
double l[N];
double dist(Fiona A,Fiona B)
{
    return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
double Directed_MST(int root,int n,int m)
{
    int i,j,k;
    int u,v,cnt;
    double ans=0;
    while(1)
    {
        for(i=1;i<=n;i++)f[i]=vis[i]=0,l[i]=inf;
        for(i=1;i<=m;i++)
        {
            u=e[i].u;v=e[i].v;
            if(l[v]>e[i].w)pre[v]=u,l[v]=e[i].w;
        }
        for(i=1;i<=n;i++)if(l[i]==inf&&i!=root)return -1;
        l[root]=cnt=0;
        for(i=1;i<=n;i++)
        {
            ans+=l[i];
            if(vis[i])continue;
            for(v=i;!vis[v]&&v!=root;vis[v]=i,v=pre[v]);
            if(v!=root&&vis[v]==i)
            {
                f[v]=++cnt;
                for(u=pre[v];u!=v;u=pre[u])f[u]=cnt;
            }
        }
        if(!cnt)break;
        for(i=1;i<=n;i++)if(!f[i])f[i]=++cnt;
            n=cnt,cnt=0,root=f[root];
        for(i=1;i<=m;i++)
        {
            u=e[i].u,v=e[i].v;
            if(f[u]!=f[v])
            {
                e[++cnt].u=f[u];
                e[cnt].v=f[v];
                e[cnt].w=e[i].w-l[v];
            }
        }
        m=cnt;
    }
    return ans;
}
int main()
{
    freopen("test.in","r",stdin);
    int i,n,m;
    double ans;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++)scanf("%lf%lf",&s[i].x,&s[i].y);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&e[i].u,&e[i].v);
            if(e[i].u!=e[i].v)e[i].w=dist(s[e[i].u],s[e[i].v]);
            else i--,m--;
        }
        ans=Directed_MST(1,n,m);
        if(ans==-1)printf("poor snoopy\n");
        else printf("%.2f\n",ans);
    }
    return 0;
}

你可能感兴趣的:(最小树形图,模板)