• Solution -「Gym 102759C」Economic One-way Roads


    (mathcal{Description})

      Link.

      给定一个含 (n) 个点 (m) 条边的简单无向图,每条边的两种定向方法各有权值,求使得图强连通且定向权值和最小的方法。

      (nle 18)

    (mathcal{Solution})

      涉及到叫做“耳分解”的知识点。

    有向图 (G=(V,E)) 是否强连通有以下判别方法:

    • 取任意 (uin V),令点集 (S={u})
    • 反复取 (x,yin S),以及连接 (x,y) 的一条有向路径 (P=lang x,u_1,cdots,u_k,y ang),满足 (u_i otin S,~iin[1,k]),并令 (Sleftarrow Scup{u_1,cdots,u_k})
    • (S=V),则 (G) 强连通;否则即找不到增广路 (P)(G) 非强连通。

    其中 (P) 就是一个“耳”,这就是“耳分解”。

    ——当然“耳”貌似最初定义于无向图。

      知道了这个构造强连通图的 trick 就极简了,首先在双向边权中随便选一个预支付代价,并令 (f(S)) 表示在 (S) 的导出子图内使 (S) 强连通的最小代价,(g(S,x,y,0/1)) 表示点集 (S) 中,当前正在构造的“耳”从 (x) 出发,希望回到 (y),不能/能 直接走 (lang x,y ang) 这条边。随便转移即可。复杂度上限是 (mathcal O(2^nn^3)),但算法本身和状态合法性带来了小常数√

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #include <cstdio>
    #include <cstring>
    
    #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
    #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
    
    const int MAXN = 18, IINF = 0x3f3f3f3f;
    int n, adj[MAXN + 5][MAXN + 5], f[1 << MAXN], g[1 << MAXN][MAXN][MAXN][2];
    
    inline void chkmin( int& a, const int b ) { b < a && ( a = b ); }
    inline int imin( const int a, const int b ) { return a < b ? a : b; }
    
    int main() {
        // freopen( "data.in", "r", stdin );
    
        scanf( "%d", &n );
        rep ( i, 0, n - 1 ) rep ( j, 0, n - 1 ) scanf( "%d", &adj[i][j] );
    
        int ans = 0;
        rep ( i, 0, n - 1 ) rep ( j, i + 1, n - 1 ) {
            if ( ~adj[i][j] ) {
                int t = imin( adj[i][j], adj[j][i] );
                ans += t, adj[i][j] -= t, adj[j][i] -= t;
            }
        }
    
        memset( f, 0x3f, sizeof f ), memset( g, 0x3f, sizeof g ), f[1] = 0;
        rep ( S, 1, ( 1 << n ) - 1 ) if ( S & 1 ) {
            rep ( u, 0, n - 1 ) if ( S >> u & 1 ) {
                rep ( v, 0, n - 1 ) if ( S >> v & 1 && ~adj[u][v] ) {
                    chkmin( f[S], g[S][u][v][1] + adj[u][v] );
                }
            }
    
            rep ( u, 0, n - 1 ) if ( S >> u & 1 ) {
                rep ( v, 0, n - 1 ) if ( S >> v & 1 ) {
                    chkmin( g[S][u][v][0], f[S] );
                }
            }
    
            rep ( u, 0, n - 1 ) if ( S >> u & 1 ) {
                rep ( v, 0, n - 1 ) if ( S >> v & 1 ) {
                    int* cur = g[S][u][v];
                    if ( cur[0] != IINF ) {
                        rep ( w, 0, n - 1 ) if ( ~adj[u][w] && !( S >> w & 1 ) ) {
                            chkmin( g[S | 1 << w][w][v][u != v],
                              cur[0] + adj[u][w] );
                        }
                    }
                    if ( cur[1] != IINF ) {
                        rep ( w, 0, n - 1 ) if ( ~adj[u][w] && !( S >> w & 1 ) ) {
                            chkmin( g[S | 1 << w][w][v][1], cur[1] + adj[u][w] );
                        }
                    }
                }
            }
        }
    
        printf( "%d
    ", f[( 1 << n ) - 1] == IINF ? -1 : ans + f[( 1 << n ) - 1] );
        return 0;
    }
    
    
  • 相关阅读:
    [Learn AF3]第二章 App Framework 3.0的组件View——AF3的驱动引擎
    [Learn AF3]第一章 如何使用App Framework 3.0 构造应用程序
    [译]Intel App Framework 3.0的变化
    手机浏览器中屏蔽img的系统右键菜单context menu
    HTML5 touche vents drag to move & AF actionsheet by longTap
    HTML5 FileReader
    【转】Gulp入门基础教程
    【Intel AF 2.1 学习笔记三】
    【Intel AF 2.1 学习笔记二】AF中的页面——Panel
    【Intel AF 2.1 学习笔记一】AF程序结构
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15145289.html
Copyright © 2020-2023  润新知