zoukankan      html  css  js  c++  java
  • poj3164 最小树形图板子题

    /*

    思路很简单,也不知道哪里错了TAT

    */

    /*
    N个点通过笛卡尔坐标表示
    根节点是1,求最小树形图 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define MAXN 105
    #define INF 0x3f3f3f3f
    using namespace std;
    struct Edge{
         int u,v;
         double cost;
         Edge(int uu=0,int vv=0,double cc=0.0):u(uu),v(vv),cost(cc){}
    }edge[MAXN*MAXN];
    struct node{
         int x,y;
    }nodes[MAXN];
    double dist(int u,int v){
         return sqrt((double)(nodes[u].x-nodes[v].x)*(nodes[u].x-nodes[v].x)+
                      (nodes[u].y-nodes[v].y)*(nodes[u].y-nodes[v].y));
    } 
    int pre[MAXN],id[MAXN],vis[MAXN];
    double in[MAXN];
    double zhuliu(int root, int nv, int ne)
    {
        double ans = 0;
        int u, v, i, cnt;
        while(true){
            //0.初始化
            for(i = 1; i <= nv; ++i) in[i] = INF;
            //1.找最小入边集
            for(i = 1; i <= ne; ++i){
                u = edge[i].u; v = edge[i].v;
                if(edge[i].cost < in[v] && u != v){
                    in[v] = edge[i].cost; pre[v] = u;
                }
            }
            for(i = 1; i <= nv; ++i)
                if(in[i]==INF && i!=root)
                    return -1;
            //2.找非根无入边点(略),因为必定有解
            //3.找环,加权,重新标号
            memset(id, -1, sizeof(id));
            memset(vis, -1, sizeof(vis));
            cnt = in[root] = 0;
            for(i = 1; i <= nv; ++i){
                ans += in[i]; v = i;
                while(vis[v] != i && v != root && id[v] == -1){
                    vis[v] = i; v = pre[v];
                }
                if(v != root && id[v] == -1){
                    for(u = pre[v]; u != v; u = pre[u])
                        id[u] = cnt;
                    id[v] = cnt++;
                }
            }
            if(cnt == 0) break; //无环,算法完成
            for(i = 1; i <= nv; ++i) 
                if(id[i] == -1) id[i] = cnt++;
            //4.缩点,遍历每一条边,重新构图
            for(i = 1; i <= ne; ++i){
                v = edge[i].v;
                edge[i].u = id[edge[i].u];
                edge[i].v = id[edge[i].v];
                if(edge[i].u != edge[i].v) edge[i].cost -= in[v];
            }
            //顶点数减少
            nv = cnt; root = id[root];
        }
        return ans;
    }
    int main(){
         int n,m,u,v;
         while(scanf("%d%d",&n,&m)==2){
             for(int i=1;i<=n;i++)
                 scanf("%d%d",&nodes[i].x,&nodes[i].y);
             int totm=0;
            for(int i=1;i<=m;i++){
                 scanf("%d%d",&u,&v);
                 if(u!=v)
                     edge[++totm]=Edge(u,v,dist(u,v));
             }
             int root=1;
             double res=zhuliu(root,n,totm);
             if(res==-1)
                 puts("poor snoopy");
             else 
                 printf("%.2lf
    ",res);
         }
         return 0;
    } 
  • 相关阅读:
    最佳调度问题_分支限界法
    运动员最佳配对问题
    最小重量机器设计问题
    实现银行家算法和先进先出算法_对文件读写数据
    n皇后问题_回溯法
    0-1背包_回溯法
    根据前序、中序、后序遍历还原二叉树
    矩阵连乘问题_动态规划
    最长公共子序列_动态规划
    最优二叉查找树_动态规划
  • 原文地址:https://www.cnblogs.com/zsben991126/p/9804947.html
Copyright © 2011-2022 走看看