zoukankan      html  css  js  c++  java
  • 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);
        }
    }
  • 相关阅读:
    AndRodi Strudio中的按钮时件
    Intent(三)向下一个活动传递数据
    Intent(二)隐式调用intent
    用PopupWindow做下拉框
    环形进度条
    Android Studio分类整理res/Layout中的布局文件(创建子目录)
    Android无需申请权限拨打电话
    使用ViewPager切换Fragment时,防止频繁调用OnCreatView
    定制 黑色描边、白色背景、带圆角 的背景
    Android 底部弹出Dialog(横向满屏)
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5474221.html
Copyright © 2011-2022 走看看