poj 3164 最小树形图

15 篇文章 0 订阅
1 篇文章 0 订阅


最小树形图。就是从根节点出发,生成能到达各个节点的最小有向图的最小生成树。。


= =第一次SB西西的用 prim算法, 哎,,显然会wa。。。。  发现生成树考点好多 。


以下是朱刘算法。。


#include <cstdio>
#include <iostream>
#include <string>
#include <cmath>
#include <cstring>
using namespace std;

const int inf = 0x3f3f3f3f;
const int N = 1111;
const double eps = 1e-5;
struct node{
	double x,y;
	void input(){
		scanf("%lf %lf",&x,&y);
	}
}P[N];
struct edge{
	int u,v;
	double w;
	edge(){}
	edge(int _u,int _v,double _w):u(_u),v(_v),w(_w){}
}e[N<<4];
double d(int u,int v){
	return sqrt((P[u].x-P[v].x)*(P[u].x-P[v].x) + (P[u].y-P[v].y)*(P[u].y-P[v].y));
}
int color[N],pre[N],vis[N];
double prv[N];
int n,m;
double solve(int root){
	double ans = 0.0;
	while(true){
		for(int i = 0;i < n;i++)
			prv[i] = inf,pre[i] = -1;
		for(int i = 0;i < m;i++){
			int u = e[i].u, v = e[i].v;
			double w = e[i].w;
			//if(v==root) continue;
			if(w < prv[v] && u != v){
				prv[v] = w;
				pre[v] = u;
			}
		}
		for(int i = 0;i < n;i++)
			if(i != root && prv[i] == inf)
				return -1;
		int cnt = 0;
		memset(vis,-1,sizeof(vis));
		memset(color,-1,sizeof(color));
		prv[root] = 0;
		for(int i = 0;i < n;i++){
			ans += prv[i];
			int v = i;
			for(; vis[v] != i && color[v]==-1 && v!= root ; v = pre[v]){
				vis[v] = i;
			}
			if(v!=root && color[v] == -1){  //判断是否存在环
				for(int u = pre[v]; u!=v; u=pre[u]){
					color[u] = cnt;
				}
				color[v] = cnt++;
			}
		}	
		if(cnt == 0) break;
		for(int i = 0;i < n;i++){
			if(color[i] == -1)
				color[i] = cnt++;
		}
		//开始进行缩点
		for(int i = 0;i < m;i++){
			int u = e[i].u , v = e[i].v ;
			double w = e[i].w;
			e[i].u = color[u];
			e[i].v = color[v];
			if(color[u] != color[v]){
				e[i].w -= prv[v];
			}
		}
		n = cnt;
		root = color[root];
	}
	return ans;
}
void init(){
	for(int i = 0 ;i < n;i++)
		P[i].input();
	for(int i = 0,u,v;i < m;i++){
		scanf("%d %d",&u,&v);
		u--,v--;
		if(u==v) e[i]=edge(u,v,inf);
		else e[i] = edge(u,v,d(u,v));
	}
}
int main(){
	while(scanf("%d %d",&n,&m)!=EOF ){
		init();
		double ans = solve(0);
		if(fabs(ans+1) < eps){
			puts("poor snoopy");
		}else printf("%.2lf\n",ans);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值