最小树形图——朱刘算法
首先问一个问题 最小生成树是用来解决有向图还是无向图问题的
最小生成树详解 见 https://blog.csdn.net/ZCY19990813/article/details/81503525
。。。。要是你回答无向图的话 可以往下面看啦
最小树形图是用来解决有向图的最小生成树问题(unidirectional 单向的)
性质:最小树形图基于贪心和缩点的思想。
正在看这篇文章 https://blog.csdn.net/lianai911/article/details/45462361
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<limits.h>
using namespace std;
const int MAXN = 110;
const int MAXM = 10010;
struct Node//存放图
{
int from;
int to;
double w;
}Edges[MAXM];
struct Node1
{
double x;
double y;
};
Node1 Point[MAXN];
double Dist(Node1 a, Node1 b)
{
double x = a.x - b.x;
double y = a.y - b.y;
return sqrt(x*x+y*y);
}
int pre[MAXN],vis[MAXN],flag[MAXN];
//flag标记缩点,标记为true,则该点被缩掉
double In[MAXN],sum;
double ZhuLiu(int root,int N,int M)
{
sum = 0; //存放最小树形图
while(true)
{
//求最短弧集合
for(int i = 0; i < N; ++i)
In[i] = INT_MAX;
for(int i = 0; i < M; ++i)
{
int u = Edges[i].from;
int v = Edges[i].to;
if(Edges[i].w < In[v] && u != v)
{
pre[v] = u;//v为终点,pre[v]存放起点
In[v] = Edges[i].w;//权值最小的边
}
}
for(int i = 0; i < N; ++i)//如果存在除root以外的孤立点,则不存在最小树形图
{
if(i == root)
continue;
if(In[i] == INT_MAX)
return -1;
}
int CntNode = 0; //新图编号
memset(flag,-1,sizeof(flag));
memset(vis,-1,sizeof(vis));
In[root] = 0;
for(int i = 0; i < N; ++i) //找环,标记每个环
{
sum += In[i];
int v = i;
while(vis[v]!=i && flag[v]==-1 && v!=root)//每个点寻找其前序点,要么最终寻找至根部,要么找到一个环
{
vis[v] = i;
v = pre[v];
}
if(v != root && flag[v] == -1) //新图重新编号
{
for(int u = pre[v]; u != v; u = pre[u])
flag[u] = CntNode;
flag[v] = CntNode++;
}
}
if(CntNode == 0) //无环,跳出
break;
for(int i = 0; i < N; ++i) //缩点
{
if(flag[i] == -1)
flag[i] = CntNode++;
}
for(int i = 0; i < M; ++i) //建立新图,更新其他点到环的距离
{
int v = Edges[i].to;
Edges[i].from = flag[Edges[i].from];
Edges[i].to = flag[Edges[i].to];
if(Edges[i].from != Edges[i].to)
Edges[i].w -= In[v];
}
N = CntNode;
root = flag[root];
}
return sum;
}
int main()
{
int x,y,N,M;
while(~scanf("%d%d",&N,&M))
{
int id = 0;
for(int i = 0; i < N; ++i)
scanf("%lf%lf",&Point[i].x,&Point[i].y);
for(int i = 0; i < M; ++i)
{
scanf("%d%d",&x,&y);
if(x == y)
continue;
x--;
y--;
Edges[id].from = x;
Edges[id].to = y;
Edges[id++].w = Dist(Point[x],Point[y]); //建立有向图
}
double ans = ZhuLiu(0,N,id);
if(ans == -1) //不能构成最小树形图
printf("poor snoopy\n");
else
printf("%.2lf\n",ans);
}
return 0;
}
~~正在更新