zoukankan      html  css  js  c++  java
  • poj 3164

    朱刘算法

    步骤:

      1、计算出每个点边权最小的边的权(如果除根以外有其他的点没有入边,则不存在最小树形图),并记下边的另一个端点(称其为这个点的前趋)

      2、沿着每个点向上走,如果在走到根或环上的点之前,就遇到走过的点,那么就出现环了。将环上的点标记一下当前环的编号,并将环上的所有边的边权加在答案里。

      3、如果在2中没有找到环,将当前图除了根以外对应的点的最小入边边权加在答案里,然后返回答案。

      4、否则,将剩下的点标号,并标记为非环点,将所有边两端的点的编号换成对应环的编号,如果目标点是一个环,将边权减少目标点对应的环中的最小入边权。

    复杂度:最坏O(N^3)

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <vector>
     4 #define oo 1e20
     5 #define N 110
     6 #define M 10100
     7 using namespace std;
     8 
     9 struct Edge {
    10     int u, v;
    11     double w;
    12     Edge(){}
    13     Edge( int u, int v, double w ):u(u),v(v),w(w){}
    14 };
    15 
    16 int n, m;
    17 double pts[N][2];
    18 int idx[N], vis[N], pre[N], inc[N];
    19 double inw[N];
    20 Edge edge[M];
    21 
    22 double getdis( int u, int v ) {
    23     int dx = pts[u][0]-pts[v][0];
    24     int dy = pts[u][1]-pts[v][1];
    25     return sqrt(dx*dx+dy*dy);
    26 }
    27 double diricted_mst( int root ) {
    28     double rt = 0.0;
    29     while(1) {
    30         //---
    31         for( int i=1; i<=n; i++ )
    32             inw[i] = oo;
    33         for( int i=0; i<m; i++ ) {
    34             Edge &e = edge[i];
    35             if( e.u==e.v ) continue;
    36             if( inw[e.v]>e.w ) {
    37                 inw[e.v]=e.w;
    38                 pre[e.v]=e.u;
    39             }
    40         }
    41         for( int i=1; i<=n; i++ ) 
    42             if( inw[i]==oo && i!=root ) 
    43                 return -1.0;
    44         //---
    45         for( int i=1; i<=n; i++ ) 
    46             vis[i] = idx[i] = 0;
    47         int cnt = 0;
    48         for( int u=1,v,s; u<=n; u++ ) {
    49             if( u==root ) continue;
    50             for( v=pre[u]; v!=root && !idx[v] && vis[v]!=u; v=pre[v] )
    51                 vis[v] = u;
    52             if( v==root || idx[v] ) continue;
    53             cnt++;
    54             s = v;
    55             for( v=pre[s]; v!=s; v=pre[v] ) {
    56                 inc[v] = true;
    57                 idx[v] = cnt;
    58                 rt += inw[v];
    59             }
    60             inc[s] = true;
    61             idx[s] = cnt;
    62             rt += inw[s];
    63         }
    64         if( cnt==0 ) {
    65             for( int u=1; u<=n; u++ ) 
    66                 if( u!=root ) 
    67                     rt += inw[u];
    68             break;
    69         }
    70         for( int u=1; u<=n; u++ )
    71             if( !idx[u] ) {
    72                 inc[u] = false;
    73                 idx[u]=++cnt;
    74             }
    75         //---
    76         for( int i=0; i<m; i++ ) {
    77             Edge &e=edge[i];
    78             if( inc[e.v] ) e.w-=inw[e.v];
    79             e.u = idx[e.u];
    80             e.v = idx[e.v];
    81         }
    82         root = idx[root];
    83         n = cnt;
    84     }
    85     return rt;
    86 }
    87 int main() {
    88     while(~scanf("%d%d",&n,&m)) {
    89         for( int i=1; i<=n; i++ )
    90             scanf( "%lf%lf", &pts[i][0], &pts[i][1] );
    91         for( int i=0,u,v; i<m; i++ ) {
    92             scanf( "%d%d", &u, &v );
    93             edge[i] = Edge(u,v,getdis(u,v));
    94         }
    95         double ans = diricted_mst(1);
    96         if( ans<0.0 ) printf( "poor snoopy
    " );
    97         else printf( "%.2f
    ", ans );
    98     }
    99 }
    View Code
  • 相关阅读:
    SqlServer 2008 R2定时备份数据库,并且发送邮件通知
    C# ICSharpCode.SharpZipLib.dll文件压缩和解压功能类整理,上传文件或下载文件很常用
    C#按回车Enter使输入焦点自动跳到下一个TextBox的方法收集
    SqlServer知识点记录分享
    C#为工作Sql而产生的字符串分割小工具(很实用,你值得拥有)
    SqlServer一张表数据导入另一张表,收藏使用,工作中更新数据错误很有用
    C#根据CPU+磁盘标号来注册软件
    C# winform调用浏览器打开页面方法分享,希望对大家有帮助
    H5 audio标签
    H5 video标签的第二种格式
  • 原文地址:https://www.cnblogs.com/idy002/p/4450617.html
Copyright © 2011-2022 走看看