zoukankan      html  css  js  c++  java
  • poj 3164 Command Network (朱刘算法)

    题目链接:

      http://poj.org/problem?id=3164

    题目大意:

      有n个点(用坐标表示)各点编号分别为1—>n,m条单向路,问能否存在一个花费价值最小的网络,能使从1点到达任一个点。

    解题思路:

      很明显的朱刘模板题,但是刚看到这个题目的时候,弱还不懂这个东西%>_<%

    最小树形图就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T,并且T中所有边的总权值最小。

    朱刘算法:当有向图中不存在自环,为除根之外的每个点选定一条入边,这条入边一定要是所有入边中最小的。所有的最小入边都选择出来了,如果这个入边集不存在有向环的话,这个集合就是该图的最小树形图。如果有自环的话就要消除自环,比如,现在我们假设分别有3-->1,权值为1 . 1-->3,权值为2 . 2-->1,权值为6 . 4-->3,权值为5. ,root为点4,存在自环1-->3-->1,现在就需要把1,3缩成一个点,则需要把4-->3边的权值5-2,2-->1边的权值变为6-1,。

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <algorithm>
      6 using namespace std;
      7 const int maxn = 110;
      8 const int N = 10010;
      9 const double Exp = 1e-10;
     10 const int INF = 0x3f3f3f3f;
     11 struct Point
     12 {
     13     double x, y;
     14     double length(Point a)
     15     {
     16         return sqrt((a.x-x)*(a.x-x)+(a.y-y)*(a.y-y));
     17     }
     18 };
     19 
     20 struct Edge
     21 {
     22     int u, v;
     23     double w;
     24 };
     25 
     26 Point point[maxn];
     27 Edge edge[N];
     28 int n, m;
     29 double directed_MST (int root)
     30 {
     31     double pre[maxn], ans = 0;
     32     //pre[i]为到i点权值最小的边值
     33     int vis[maxn], id[maxn], pr[maxn];
     34     //vis[i]为i点是否在当前的数上,id[i]为i点是否在自环内,
     35     int u, v;
     36     while (true)
     37     {
     38         for (int i=1; i<=n; i++)
     39             pre[i] = INF;
     40         for (int i=0; i<m; i++)
     41         {
     42             u = edge[i].u;
     43             v = edge[i].v;
     44             if (edge[i].w<pre[v] && u!=v)
     45             {
     46                 pre[v] = edge[i].w;
     47                 pr[v] = u;//到v点前驱
     48             }
     49         }
     50         for (int i=1; i<=n; i++)
     51         {
     52             if (i == root)
     53                 continue;
     54             if (pre[i] == INF)
     55                 return -1;//没有点与i相连,不存在最小树形图
     56         }
     57         memset (vis, -1, sizeof(vis));
     58         memset (id, -1, sizeof(id));
     59         int cru = 1;//对现存的点从新编号
     60         pre[root] = 0;
     61         for (int i=1; i<=n; i++)
     62         {
     63             ans += pre[i];
     64             v = i;
     65             while (vis[v]!=i && id[v]==-1 && v!=root)
     66             {//向树上加点
     67                 vis[v] = i;
     68                 v = pr[v];
     69             }
     70             if (v!=root && id[v]==-1)
     71             {//存在自环,并且把环变成一个点
     72                 for (u=pr[v]; u!=v; u=pr[u])
     73                     id[u] = cru;
     74                 id[u] = cru ++;
     75             }
     76         }
     77         if (cru == 1)
     78             break;//不存在自环
     79         for (int i=1; i<=n; i++)
     80             if (id[i] == -1)
     81             id[i] = cru ++;//对不在自环上的点编号
     82         for (int i=0; i<m; i++)
     83         {//把自环缩成一个点后,需要改变边的权
     84             u = edge[i].u;
     85             v = edge[i].v;
     86             edge[i].u = id[u];
     87             edge[i].v = id[v];
     88             if (id[u] != id[v])
     89                 edge[i].w -= pre[v];
     90         }//缩点后点数改变,根节点改变
     91         n = cru - 1;
     92         root = id[root];
     93     }
     94     return ans;
     95 }
     96 int main ()
     97 {
     98     while (scanf ("%d %d", &n, &m) != EOF)
     99     {
    100         for (int i=1; i<=n; i++)
    101             scanf ("%lf %lf", &point[i].x, &point[i].y);
    102 
    103         for (int i=0; i<m; i++)
    104         {
    105             int u, v;
    106             scanf ("%d %d", &u, &v);
    107             edge[i].u = u;
    108             edge[i].v = v;
    109             if (u == v)
    110                 edge[i].w = INF;
    111             else
    112                 edge[i].w = point[u].length(point[v]);
    113         }
    114         double num = directed_MST(1);
    115         if (num+1< Exp)
    116             printf ("poor snoopy
    ");
    117         else
    118             printf ("%.2f
    ", num);
    119     }
    120     return 0;
    121 }
    本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    深入A标签点击触发事件而不跳转的详解
    js、css、html判断浏览器的各种版本
    深入理解this对象
    背景透明文字不透明的最佳方法兼容IE(以背景黑色透明度0.5为例)
    解决ie6支持最大高度最小高度的方法
    js点击更多显示更多内容效果
    artdialog关闭弹出窗口
    (巧用)事件代理
    CSS3盒模型display:-webkit-box;的使用
    文件上传input type="file"样式美化
  • 原文地址:https://www.cnblogs.com/alihenaixiao/p/4570131.html
Copyright © 2011-2022 走看看