poj 3264 Command Network(最小树形图)

有一副有向图,要求从根节点起能访问到所有的结点,且路径最短。即求最小树形图。

算法位朱刘算法,

裸的最小树形图,用朱—刘算法解决,具体实现过程如下:算法一开始先判断从固定根开始是否可达所有原图中的点,若不可,则一定不存在最小树形图。这一步是一个很随便的搜索,写多搓都行,不加废话。第二步,遍历所有的边,从中找出除根结点外各点的最小入边,累加权值,构成新图。接着判断该图是否存在环。若不存在,则该图便是所求最小树型图,当前权为最小权。否则对环缩点,然后回到第二步继续判断。简化就是三个过程:找边—>找环—>缩点;


#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const double inf=200000000;
const int maxn = 110;
typedef double type;
struct Point{
    double x,y;
}p[maxn];
struct Node{
    int u,v;
    type w;
}node[maxn*maxn];
int pre[maxn],id[maxn],vis[maxn],n,m;
type in[maxn];
double dis(Point a,Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
type mst(int root,int v,int e){
    type ret=0;
    while(true){
        for(int i=0;i<v;i++) in[i]=inf;
        for(int i=0;i<e;i++){
            int u=node[i].u;
            int v=node[i].v;
            if(node[i].w<in[v] && u!=v){
                pre[v]=u;
                in[v]=node[i].w;
            }
        }
        for(int i=0;i<v;i++){
            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<v;i++)
        {
            ret+=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<v;i++){
            if(id[i]==-1) id[i]=cnt++;
        }
        for(int i=0;i<e;i++){
            int u=node[i].u;
            int v=node[i].v;
            node[i].u=id[u];
            node[i].v=id[v];
            if(id[u] != id[v]) node[i].w-=in[v];
        }
        v=cnt;
        root=id[root];
    }
    return ret;
}




int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        for(int i=0;i<m;i++){
            scanf("%d%d",&node[i].u,&node[i].v);
            node[i].u--;
            node[i].v--;
            if(node[i].u!=node[i].v) node[i].w=dis(p[node[i].u],p[node[i].v]);
            else node[i].w=inf;
        }
        type ans=mst(0,n,m);
        if(ans==-1) printf("poor snoopy\n");
        else printf("%.2f\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值