您的位置:首页 > 其它

【最小树形图】Command Network poj 3164

2016-08-11 20:46 417 查看
题意:求有向的最小生成树,没有输出“poor …”。

我也是初学最小树形图,我看了别人的博客和一些资料,对于我这样的新手来说,我觉得如果我不去一步一步琢磨他们的代码,还真难理解,一说明他们写的不够详细,对新手来说没办法一下理解。我从新手的角度来重新写一遍,以我的表达能力可能不能确保能让你们完全理解,将就下拉。

最小树形图就是有向的最小生成树。

首先来想想,为什么我们没办法用prim,kruskal来做有向的最小生成树。首先prim,存在一个致命的问题,它用于存两点距离的数组只能存一个值,所以只能表示双向;kruskal它将最小的边一个接一个合并,有向图要考虑方向,而其算法必须方向一致。

那么最小树形图怎么求?

首先他除起始点外找到所有值最小的入度边,如果有点是没有入度边的话,那么证明这个点怎么也无法经过,那么就没有最小树形图了。

然后找环,如果没有环,那么就直接能连成一条最小树形图了,如果有环(比如:1->2, 2 ->3, 3->1),那么我们可以将环看成一个点,(重新编号时,一个环里的数编号一样),那么再把不是环的点,点到这个环,点到点 的最小距离更新下,再重复检查重新编号后有无环,直到无环。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
const double PI = acos(-1.0);
const int mod = 1e9 + 7;
const int N = 10010;
int n,m;

struct Point
{
double x,y;
}point[110];
struct Ver
{
int a,b;
double w;
}ver
;
double Dis(Point a,Point b)
{
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}

double in
;   //最小入度边
int fa
;      //它的前一个数,也就是指向它的数
int ha
,vis
;  //ha[]是数的重新编号,vis[]是表示在i为起点时有无使用过。
double zhuliu(int root)
{
double ans = 0;
while(1)
{
for(int i = 0; i < n; i++)
in[i] = INF;
memset(fa,-1,sizeof(fa));
for(int i = 0; i < m; i++)// 最小入度边
{
//            if(ver[i].w == -1)
//                continue;
int to = ver[i].b;
if(ver[i].w < in[to] && ver[i].a != ver[i].b)
{
in[to] = ver[i].w;
fa[to] = ver[i].a;
}
}
for(int i = 0; i < n; i++)
{
if(i != root && in[i] == INF)// 除根点,有点入度为0.
return -1;
}
int cnt = 0;
in[root] = 0;
memset(ha,-1,sizeof(ha));
memset(vis,-1,sizeof(vis));
for(int i = 0; i < n; i++)//找出环编号
{
ans += in[i];
int v = i;
while(v != root && ha[v] == -1 && vis[v] != i)
{
vis[v] = i;
v = fa[v];
}
if(v != root && ha[v] == -1)//是环,缩点
{
for(int j = fa[v]; j != v; j = fa[j])
ha[j] = cnt;
ha[v] = cnt++;
}
}
if(cnt == 0)
break;
for(int i = 0; i < n; i++)
if(ha[i] == -1)    //不是环的还是-1
ha[i] = cnt++; //编号
for(int i = 0; i < m; i++) //更新其他点到环的最小距离
{
int temp = ver[i].b;
ver[i].a = ha[ver[i].a];
ver[i].b = ha[ver[i].b];
if(ver[i].a != ver[i].b)
ver[i].w -= in[temp];
}
n = cnt;
root = ha[root];
}
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(ver,0,sizeof(ver));
for(int i = 0; i < n; i++)
scanf("%lf%lf",&point[i].x,&point[i].y);
for(int i = 0; i < m; i++)
{
int from,to;
scanf("%d%d",&from,&to);
ver[i].a = from-1;
ver[i].b = to-1;
if(from == to)
ver[i].w = -1;
ver[i].w = Dis(point[from-1],point[to-1]);
}
double ans = zhuliu(0);
if(ans == -1)
puts("poor snoopy");
else
printf("%.2lf\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: