最小树形图。就是从根节点出发,生成能到达各个节点的最小有向图的最小生成树。。
= =第一次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;
}