zoukankan      html  css  js  c++  java
  • hdu 2121

    朱刘算法求无根最小树形图

    可以任意选一个根,求最小的权和以及当时的根。

    先建一个超级根,它连向所有点,边权为所有边的边权和加1(即sumw+1),然后求以它为根的最小树形图,再根据树形图权和与2*(sumw+1)的关系判断是否存在解(如果大于等于就不存在,否则存在)。

    至于求对应的原图中的根,我们发现自始自终,超级根都不可能在一个环中,并且在最有一个状态,一定是一个没有环的树形图,该图中与前趋为超级根的点,就是原图中的根所在的环缩成的点,怎么得到具体是哪一个点呢,我们可以记下那条边在最开始指向的是哪个点,那个点就是原图中的根(可以根据缩点的正确性证明它的正确性)。

     1 #include <cstdio>
     2 #define oo 0x7FFFFFFF
     3 #define N 1010
     4 #define M 11010
     5 
     6 struct Edge {
     7     int u, v, w;
     8     int sv;
     9     Edge(){}
    10     Edge( int u, int v, int w ):u(u),v(v),w(w),sv(v){}
    11 };
    12 
    13 int n, m;
    14 int inw[N], inc[N], pre[N], idx[N], vis[N], rsv;
    15 Edge edge[M];
    16 
    17 int directed_mst( int root ) {
    18     int rt = 0;
    19     while(1) {
    20         //    inw pre 
    21         for( int i=1; i<=n; i++ )
    22             inw[i] = oo;
    23         for( int i=1; i<=m; i++ ) {
    24             Edge &e = edge[i];
    25             if( inw[e.v]>e.w ) {
    26                 inw[e.v]=e.w;
    27                 pre[e.v]=e.u;
    28                 if( e.u==root ) rsv=e.sv;
    29             }
    30         }
    31         //    inc idx
    32         int cnt = 0;
    33         for( int i=1; i<=n; i++ )
    34             idx[i] = vis[i] = 0;
    35         for( int i=1,u,v; i<=n; i++ ) {
    36             if( i==root ) continue;
    37             for( u=pre[i]; u!=root && !idx[u] && vis[u]!=i; u=pre[u] )
    38                 vis[u]=i;
    39             if( u==root || idx[u] ) continue;
    40             cnt++;
    41             for( v=pre[u]; v!=u; v=pre[v] ) {
    42                 idx[v] = cnt;
    43                 inc[v] = true;
    44                 rt += inw[v];
    45             }
    46             idx[u] = cnt;
    47             inc[u] = true;
    48             rt += inw[u];
    49         }
    50         if( cnt==0 ) {
    51             for( int i=1; i<=n; i++ ) 
    52                 if( i!=root ) 
    53                     rt += inw[i];
    54             break;
    55         } else {
    56             for( int i=1; i<=n; i++ )
    57                 if( !idx[i] ) {
    58                     idx[i] = ++cnt;
    59                     inc[i] = false;
    60                 }
    61         }
    62         //    edge
    63         int j=0;
    64         for( int i=1; i<=m; i++ ) {
    65             Edge &e = edge[i];
    66             if( inc[e.v] ) e.w-=inw[e.v];
    67             e.u = idx[e.u];
    68             e.v = idx[e.v];
    69             if( e.u!=e.v ) edge[++j]=edge[i];
    70         }
    71         root = idx[root];
    72         n = cnt;
    73         m = j;
    74     }
    75     return rt;
    76 }
    77 
    78 int main() {
    79     while( scanf("%d%d",&n,&m)==2 ) {
    80         int mm=0, sw=0;
    81         for( int i=1,u,v,w; i<=m; i++ ) {
    82             scanf( "%d%d%d", &u, &v, &w );
    83             if( u==v ) continue;
    84             u++, v++;
    85             edge[++mm] = Edge(u,v,w);
    86             sw+=w;
    87         }
    88         for( int i=1; i<=n; i++ ) 
    89             edge[++mm] = Edge(n+1,i,sw+1);
    90         m = mm;
    91         n = n+1;
    92         int ans = directed_mst(n)-sw-1;
    93         if( ans>=sw+1 ) printf( "impossible
    " );
    94         else printf( "%d %d
    ", ans, rsv-1 );
    95         printf( "
    " );
    96     }
    97 }
    View Code
  • 相关阅读:
    Java Jsoup Spider抓取数据入库
    DevOps详解
    七款做好DevOps的强大工具
    DevOps 初学者的入门指南
    DevOps必备的20款顶级工具
    Docker 三大核心工具
    Deploying Docker images via SSH
    Shell实现判断进程是否存在并重新启动脚本
    记录:50多行程序中找出多写的一个字母e
    Android 平板中 自己定义键盘(popuwindow) 居于屏幕左下方 仿微信的password输入界面
  • 原文地址:https://www.cnblogs.com/idy002/p/4450917.html
Copyright © 2011-2022 走看看