BZOJ2260 商店购物 BZOJ4349 最小树形图 坠小树形图 朱刘算法

大家都很强, 可与之共勉 。

惊了,我以前朱刘算法的模板是错的!!!!

题意:
  您要买 n 种商品,每一种商品都有价格和需求量,有m个优惠条件,以 a,b,p 给出表示您买了 a 商品之后b商品的价格就会变成 p ,(p<)。请问您卖完这些东西最少花费多少?
题解:

  坠小树形图,先跑出坠小树形图。确定每个东西买一个的最小总花费,然后所有东西一定可以以最小单价买到,累加就好了。
  板子不对TTTTTTTTTTTTTTTLE

双倍经验题 BZOJ4349

/**************************************************************
    Problem: 2260
    User: Lazer2001
    Language: C++
    Result: Accepted
    Time:16 ms
    Memory:7932 kb
****************************************************************/

# include <bits/stdc++.h>

const int N = 100010 ;

class DMST  {
    private :
        double in [N] ;
        int id [N], pre [N], vis [N] ;

        struct edge  {
            int u, v ; double c ;
        } g [N << 1] ;

        int ecnt ;

        inline double Zhuliu_algorithm ( int root, int n )  {
            double rt ( 0 ) ;
            register int i, u, v ;
            for ( ; ; )  {
                for ( i = 1 ; i <= n ; ++ i )  in [i] = 1e10 ;
                for ( i = 1 ; i <= ecnt ; ++ i )  {
                    u = g [i].u, v = g [i].v ;
                    if ( g [i].c < in [v] && ( u ^ v ) )  {
                        in [v] = g [i].c ;
                        pre [v] = u ;
                    }
                }
                for ( i = 1 ; i <= n ; ++ i )  {
                    if ( i != root && in [i] == 1e10 ) return -1 ;
                }
                int cnt ( 1 ) ;
                memset ( id, -1, sizeof ( int ) * ( n + 1 ) ) ;
                memset ( vis, -1, sizeof ( int ) * ( n + 1 ) ) ;
                in [root] = 0 ;
                for ( i = 1 ; i <= n ; ++ i )  {
                    rt += in [i] ;
                    int v = i ;
                    while ( vis [v] != i && id [v] == -1 && v != root )  {
                        vis [v] = i ;
                        v = pre [v] ;
                    }
                    if ( v != root && id [v] == -1 )  {
                        for ( u = pre [v] ; u != v; u = pre [u] )
                            id [u] = cnt ;
                        id [v] = cnt ++ ;
                    }   
                }
                if ( cnt == 1 ) return rt ;  //break ;
                for ( i = 1 ; i <= n ; ++ i )   if ( id [i] == -1 ) id [i] = cnt ++ ;
                for ( i = 1 ; i <= ecnt ; ++ i )  {
                    v = g [i].v ;
                    g [i].v = id [g [i].v] ;
                    g [i].u = id [g [i].u] ;
                    if ( g [i].u ^ g [i].v )  {
                        g [i].c -= in [v] ;
                    }
                }

                n = cnt - 1 ;
                root = id [root] ;
            }
        //  return rt ;
        }
    public :

        DMST ( )  { ecnt = 0 ; }

        inline void add_edge ( int u, int v, double w )  {
            g [++ ecnt] = ( edge )  {  u, v, w  } ;
        }

        inline double main ( int root, int n )  {
            return Zhuliu_algorithm ( root, n ) ;
        }
} T ;

double c [N] ;
int need [N] ;
int id [N] ;

int main ( )  {
    int n ;
    scanf ( "%d", & n ) ;
    int cnt ( 0 ) ;
    for ( int i = 1 ; i <= n ; ++ i )  {
        scanf ( "%lf%d", c + i, need + i ) ;
        if ( need [i] )  id [i] = ++ cnt ;
    }

    int root = cnt + 1 ; // cnt ;

    for ( int i = 1 ; i <= n ; ++ i )  if ( id [i] )  T.add_edge ( root, id [i], c [i] ) ; // c [i]...

    int k ;
    scanf ( "%d", & k ) ;
    while ( k -- )  {
        int u, v ; double cost ;
        scanf ( "%d%d%lf", & u, & v, & cost ) ;
        if ( ( ! id [u] ) || ( ! id [v] ) )  continue ;
        if ( cost < c [v] )  c [v] = cost ;
        T.add_edge ( id [u], id [v], cost ) ;
    }

    double ans = T.main ( root, cnt + 1 ) ;
    for ( int i = 1 ; i <= n ; ++ i )
        if ( need [i] > 1 )  {
            ans += 1.0 * ( need [i] - 1 ) * c [i] ;
        }

    printf ( "%.2lf\n", ans ) ;

    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值