【最小树形图】Command Network poj 3164
2016-08-11 20:46
417 查看
题意:求有向的最小生成树,没有输出“poor …”。
我也是初学最小树形图,我看了别人的博客和一些资料,对于我这样的新手来说,我觉得如果我不去一步一步琢磨他们的代码,还真难理解,一说明他们写的不够详细,对新手来说没办法一下理解。我从新手的角度来重新写一遍,以我的表达能力可能不能确保能让你们完全理解,将就下拉。
最小树形图就是有向的最小生成树。
首先来想想,为什么我们没办法用prim,kruskal来做有向的最小生成树。首先prim,存在一个致命的问题,它用于存两点距离的数组只能存一个值,所以只能表示双向;kruskal它将最小的边一个接一个合并,有向图要考虑方向,而其算法必须方向一致。
那么最小树形图怎么求?
首先他除起始点外找到所有值最小的入度边,如果有点是没有入度边的话,那么证明这个点怎么也无法经过,那么就没有最小树形图了。
然后找环,如果没有环,那么就直接能连成一条最小树形图了,如果有环(比如:1->2, 2 ->3, 3->1),那么我们可以将环看成一个点,(重新编号时,一个环里的数编号一样),那么再把不是环的点,点到这个环,点到点 的最小距离更新下,再重复检查重新编号后有无环,直到无环。
我也是初学最小树形图,我看了别人的博客和一些资料,对于我这样的新手来说,我觉得如果我不去一步一步琢磨他们的代码,还真难理解,一说明他们写的不够详细,对新手来说没办法一下理解。我从新手的角度来重新写一遍,以我的表达能力可能不能确保能让你们完全理解,将就下拉。
最小树形图就是有向的最小生成树。
首先来想想,为什么我们没办法用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; }
相关文章推荐
- Command Network POJ - 3164(根为1的最小树形图)
- POJ 3164 Command Network(最小树形图)
- POJ 3164——Command Network——————【最小树形图、固定根】
- POJ 3164 Command Network (最小树形图-朱刘算法)
- 最小树形图 Command Network POJ - 3164
- 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 (最小树形图模板,3级)
- POJ 3164 Command Network(最小树形图)
- POJ 3164:Command Network(最小树形图)
- POJ 3164 Command Network(最小树形图模板)
- POJ 3164 Command Network (最小树形图模板,3级)
- POJ 3164 Command Network 最小树形图模板 朱-刘算法
- POJ 3164 Command Network 最小树形图
- poj 3164 Command Network#有向最小树形图