1. 程式人生 > >poj3164 最小樹形圖板子題

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\n",res); } return 0; }