POJ-3164 Command Network 最小树形图 朱刘算法

朱刘算法

参考之 http://blog.csdn.net/wsniyufang/article/details/6747392

http://blog.csdn.net/ac_lion/article/details/8104461



#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
using namespace std;
const int maxn = 115;
#define type double 
const type inf = 1<<30;
int n,m;
struct point
{
	double x,y;
}p[maxn];
struct node
{
	int u,v;
	type w;
}E[maxn*maxn];
int pre[maxn],id[maxn],vis[maxn];//id为缩点后的点
type in[maxn];					//in[i]点i的最小入边权
double getdis(point a,point b)  
{  
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));  
}
type Directed_MST(int root,int nv,int ne) {  
    type ret = 0;  
    while( true ) {  
        //1.找最小入边  
        for(int i = 0; i < nv; i ++ ) in[i] = inf;  
        for(int i = 0; i < ne; i++){  
            int u = E[i].u;  
            int v = E[i].v;  
            if(E[i].w < in[v] && u != v) {  
                pre[v] = u;  
                in[v] = E[i].w;  
            }  
        }  
        for( int i = 0; i < nv; i ++ ) {  
            if( i == root ) continue;  
            if( in[i] == inf )    return -1;//除了跟以外有点没有入边,则根无法到达它  
        }  
        //2.找环  
        int cntnode = 0;  
		memset(id,-1,sizeof(id));  
		memset(vis,-1,sizeof(vis));  
        in[root] = 0;  
        for(int i = 0; i < nv; 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] = cntnode;  
                }  
                id[v] = cntnode ++;  
            }  
        }  
        if( cntnode == 0 )    break;//无环  
        for( int i = 0; i < nv; i ++ ) 
			if( id[i] == -1 ) {  
				id[i] = cntnode ++;  
        }  
        //3.缩点,重新标记  
        for( int i = 0; i < ne; i ++) {  
            int v = E[i].v;           //注意 E[i].v 下面改变了
            E[i].u = id[E[i].u];  
            E[i].v = id[E[i].v];  
            if(E[i].u != E[i].v) {  
                E[i].w -= in[v];      //这里的v不能直接用E[i].v
            }  
        }  
        nv = cntnode;  
        root = id[root];  
    }  
    return ret;  
}  
int main()
{
	//freopen("data.txt","r",stdin);
    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",&E[i].u,&E[i].v);
			E[i].u --;	E[i].v --;
			if( E[i].u != E[i].v )
				E[i].w = getdis(p[E[i].u],p[E[i].v]);
			else
				E[i].w = inf;
		}
		type ans = Directed_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、付费专栏及课程。

余额充值