最小树形图,就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T,并且T中所有边的总权值最小。
朱刘算法模板题
#include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <stack> #include <queue> #include <cmath> #include <vector> using namespace std; typedef long long LL; const int N=1e2+5; const int INF=0x3f3f3f3f; struct Node{ double x,y; }p[N]; struct Edge{ int u,v; double w; }edge[N*N]; double in[N]; int id[N],vis[N],pre[N],n,m; double dis(int u,int v){ double x=p[u].x-p[v].x,y=p[u].y-p[v].y; return sqrt(x*x+y*y); } double zhuliu(int rt,int n,int m){ double ret=0; while(1){ for(int i=1;i<=n;++i)in[i]=INF; for(int i=1;i<=m;++i){ if(edge[i].u!=edge[i].v&&edge[i].w<in[edge[i].v]){ pre[edge[i].v]=edge[i].u; in[edge[i].v]=edge[i].w; } } for(int i=1;i<=n;++i) if(i!=rt&&in[i]==INF)return -1; int cnt=0; memset(id,-1,sizeof(id)); memset(vis,-1,sizeof(vis)); in[rt]=0; for(int i=1;i<=n;++i){ ret+=in[i]; int v=i; while(vis[v]!=i&&id[v]==-1&&v!=rt){ vis[v]=i; v=pre[v]; } if(v!=rt&&id[v]==-1){ ++cnt; for(int u=pre[v];u!=v;u=pre[u]) id[u]=cnt; id[v]=cnt; } } if(cnt==0)break; for(int i=1;i<=n;++i) if(id[i]==-1)id[i]=++cnt; for(int i=1;i<=m;++i){ int u=edge[i].u,v=edge[i].v; edge[i].u=id[u]; edge[i].v=id[v]; if(id[u]!=id[v])edge[i].w-=in[v]; } n=cnt; rt=id[rt]; } return ret; } int main() { while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;++i)scanf("%lf%lf",&p[i].x,&p[i].y); for(int i=1;i<=m;++i){ scanf("%d%d",&edge[i].u,&edge[i].v); edge[i].w=INF; if(edge[i].u!=edge[i].v)edge[i].w=dis(edge[i].u,edge[i].v); } double ans=zhuliu(1,n,m); if(ans<0)printf("poor snoopy\n"); else printf("%.2f\n",ans); } return 0; }
时间: 2024-10-09 21:25:30