ZOJ 2008 Invitation Cards

使用最小堆dijk求最短路径的标准算法,时间复杂度为elogv。

 

#include  < cstdio >
#include 
< string >

#define  INF 2000000000
#define  MAXN 500000
#define  MAXM 500000

int  T, N, M;
int  dist[MAXN], next[ 2 ][MAXM], num[ 2 ][MAXN], heap[MAXN], idx[MAXN], used[MAXN];
int  size, src, dst;

typedef 
struct
{
    
int u, v, w;
}
 Edge;
Edge e[
2 ][MAXM];


void  update (  int  );
int  get_top ();

void  printHeap ()
{
    
int i;
    
for ( i = 1; i <= size; i ++ )
        printf ( 
"%d ", heap[i] );
    printf ( 
" " );
}


void  id ()
{
    
int i;
    
for ( i = 0; i <= N; i ++ )
        dist[i] 
= INF;
}


void  init ()
{
    scanf ( 
"%d%d"&N, &M );
    memset ( num, 
0x00sizeof ( num ) );
    memset ( idx, 
0x00sizeof ( idx ) );
    memset ( used, 
0x00sizeof ( used ) );
    
int i, x, y, w;
    
// 链表存储
    for ( i = 1; i <= M; i ++ )
    
{
        scanf ( 
"%d%d%d"&x, &y, &w );
        e[
0][i].u = x, e[0][i].v = y, e[0][i].w = w;
        e[
1][i].u = y, e[1][i].v = x, e[1][i].w = w;
        next[
0][i] = num[0][x], num[0][x] = i, next[1][i] = num[1][y], num[1][y] = i;
    }

}


int  dijk ()
{
    
int ans = 0;
    
// 两次dijk,求对于点1,出路径和返回路径最短
    id ();
    size 
= 0, src = 1;
    dist[src] 
= 0, used[src] = 1, heap[++ size] = 1, idx[src] = 1;
    
int i;
    
while ( true )
    
{
        
if ( size == 0 )
            
break;
        
int u, v;
        u 
= get_top ();
        used[u] 
= 1;
        
for ( i = num[0][u]; i; i = next[0][i] )
        
{
            v 
= e[0][i].v;
            
if ( !used[v] && dist[v] > dist[u] + e[0][i].w )
            
{
                
if ( idx[v] == 0 )
                
{
                    heap[
++ size] = v;
                    idx[v] 
= size;
                }

                dist[v] 
= dist[u] + e[0][i].w;
                update ( v );
            }

        }

    }

    
for ( i = 2; i <= N; i ++ )
        ans 
+= dist[i];
    
    id ();
    memset ( used, 
0x00sizeof ( used ) );
    memset ( idx, 
0x00sizeof ( idx ) );
    size 
= 0, src = 1;
    dist[src] 
= 0, used[src] = 1, heap[++ size] = 1, idx[src] = 1;
    
while ( true )
    
{
        
if ( size == 0 )
            
break;
        
int u, v;
        u 
= get_top ();
        used[u] 
= 1;
        
for ( i = num[1][u]; i; i = next[1][i] )
        
{
            v 
= e[1][i].v;
            
if ( !used[v] && dist[v] > dist[u] + e[1][i].w )
            
{
                
if ( idx[v] == 0 )
                
{
                    heap[
++ size] = v;
                    idx[v] 
= size;
                }

                dist[v] 
= dist[u] + e[1][i].w;
                update ( v );
            }

        }

    }

    
for ( i = 2; i <= N; i ++ )
        ans 
+= dist[i];
    
    
return ans;
}


int  main ()
{
    
//freopen ( "in.txt", "r", stdin );
    scanf ( "%d"&T );
    
int i;
    
for ( i = 0; i < T; i ++ )
    
{
        init ();
        printf ( 
"%d ", dijk () );
    }

    
return 0;
}


int  get_top ()
{
    
int ret = heap[1];
    
int p = 1, q = 2, r = heap[size --];        //p 当前点 q 父节点,下同
    while ( q <= size )
    
{
        
if ( q < size && dist[heap[q]] > dist[heap[q + 1]] )
            q 
++;
        
if ( dist[r] > dist[heap[q]] )
        
{
            idx[heap[q]] 
= p;
            heap[p] 
= heap[q];
            p 
= q, q <<= 1;
        }

        
else
            
break;
    }

    idx[r] 
= p, heap[p] = r;
    
return ret;
}


void  update (  int  r )
{
    
int q = idx[r], p = q >> 1;        
    
while ( p && dist[r] < dist[heap[p]] )
    
{
        heap[q] 
= heap[p], idx[heap[p]] = q;
        q 
= q >> 1, p = p >> 1;
    }

    heap[q] 
= r, idx[r] = q;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值