Command Network poj 3164 (最小树形图)
来源:互联网 发布:linux配置ntp时间同步 编辑:程序博客网 时间:2024/06/11 07:26
题意:求有向的最小生成树,没有输出“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 0x3f3f3f3ftypedef 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[N];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[N]; //最小入度边int fa[N]; //它的前一个数,也就是指向它的数int ha[N],vis[N]; //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;}
0 0
- poj 3164 Command Network 最小树形图
- POJ 3164 Command Network 最小树形图
- 最小树形图 【poj 3164 Command Network】
- POJ 3164 Command Network (最小树形图)
- poj 3164 Command Network 最小树形图
- [POJ 3164]Command Network[最小树形图]
- POJ 3164 Command Network 最小树形图
- POJ 3164 Command Network 最小树形图
- POJ 3164 Command Network【最小树形图】
- Poj 3164 Command Network【最小树形图】
- POJ 3164 Command Network(最小树形图)
- 【poj 3164】Command Network 最小树形图
- Command Network poj 3164 (最小树形图)
- poj 3164 Command Network【最小树形图】
- poj Command Network 最小树形图
- 最小树形图 Command Network POJ
- poj 3164 Command Network#有向最小树形图
- poj 3164 Command Network(最小树形图模板题)
- 关于String内存分配的深入探讨 (转)
- Pointer and Const
- C++ 模板函数
- SDUT oj 数据结构实验之查找一:二叉排序树
- 常用框架的说明
- Command Network poj 3164 (最小树形图)
- 全排列
- float与double内存中的表示
- 随机森林原理与应用
- java非静态方法为什么不能被子类覆盖为静态方法
- 二叉树和为某一值的路径
- Java7并发编程--5、并发集合
- Editplus从下载到使用
- exec函数族实例解析