最近写 Prim 和 Disjkstra , 顺便复习一下堆和优先级队列的知识 :
#include <bits/stdc++.h>
using namespace std ;
#define Init_Data 0 // 设置初始数据
typedef int Data_type ; // 数据类型, 在本程序只是单一类型
class My_Priority_queue{// 优先级队列默认为小顶堆
private:
int Max_size ; // 优先级队列的最大容量
int n ; // 优先级队列当前的元素个数
Data_type *a ; // 数据指针, 顺序表
public:
My_Priority_queue() ; // 构造函数
~My_Priority_queue() ; // 析构函数
void push( Data_type weight ) ; // 往优先级队列中 push 数据
void pop() ; // pop 堆顶
Data_type top() ; // 访问栈顶元素
bool empty() ; // 判断堆是否为空
int size() ; // 堆大小
void Shift_down( int u ) ; // 递归 堆向下调整
void Shift_down_2( int u ) ; // 非递归 堆向下调整
} ;
My_Priority_queue::My_Priority_queue(){
n = 0 ;
Max_size = 256 ;
a = new Data_type[Max_size] ;
if( a ){
for( int i = 0 ; i < Max_size ; ++i ) // 初始化
a[i] = Init_Data ;
cout << endl << "优先级队列初始化准备完毕 " << endl ;
}
else
cout << endl << "内存分配失败 !" << endl ;
}
My_Priority_queue::~My_Priority_queue(){
if( a )
delete a , a = NULL ; // 队列分配了空间 , 释放掉
cout << endl << "优先级队列的内存已释放完毕 " << endl ;
}
void My_Priority_queue::push( Data_type weight ){
if( n+1 > Max_size ){
cout << endl << "优先级队列重新分配空间" << endl ;
int cur = Max_size ;
Max_size += cur ;
Data_type *temp = new Data_type[Max_size] ;
for( int i = 0 ; i < Max_size ; ++i )
temp[i] = Init_Data ;
for( int i = 1 ; i <= cur ; ++i ) // 保存原始数据
temp[i] = a[i] ;
delete a , a = NULL ;
a = temp ;
temp = NULL ;
cout << endl << "优先级队列已重新就绪" << endl ;
}
a[++n] = weight ; // push 压入的新元素放在末尾
int parent = n >> 1 , i = n ; // 因为前面的都是小顶堆
while( parent ){
if( a[i] < a[parent] )
swap( a[i] , a[parent] ) ;
i = parent ;
parent /= 2 ; // 从下向上调整, 只要和父亲相比
}
}
void My_Priority_queue::pop(){
if( empty() ){
cout << "It's empty !" << endl ;
return ;
}
swap( a[1] , a[n--] ) ; // 把最后一个元素交换到堆顶, 堆大小 -1
Shift_down_2( 1 ) ; // 从堆顶开始向下调整
}
Data_type My_Priority_queue::top(){ // 取堆顶元素 , 优先级队列中最小的元素
return a[1] ;
}
bool My_Priority_queue::empty(){ // 判断优先级队列 ( 堆 ) 是否为空
return n < 1 ;
}
int My_Priority_queue::size(){ // 取优先级队列元素个数
return n ;
}
void My_Priority_queue::Shift_down( int u ){ // 递归
int ans = u ;
if( 2*u <= n && a[2*u] < a[ans] ) // 比较左孩子
ans = 2*u ;
if( 2*u+1 <= n && a[2*u+1] < a[ans] ) // 比较右孩子
ans = 2*u+1 ;
if( ans != u ) // 最小的元素 a[ans] 在两个孩子当中
swap( a[ans] , a[u] ) , Shift_down( ans ) ; // 交换 , 继续向下调整
}
void My_Priority_queue::Shift_down_2( int u ){ // 非递归
int i = 2*u ;
for( ; i <= n ; i = 2*u ){ // 每次交换之后, i 都恢复为 2*u , 这时候的 u 不是原来的 u
if( i+1 <= n && a[i+1] < a[i] ) // 比较右孩子
++i ;
if( a[i] >= a[u] ) return ; // 如果最小的元素就是自己, 不在孩子当中
swap( a[i] , a[u] ) ;
u = i ; // 交换最小的元素 , 更大的继续向下调整
}
}
int main(){
My_Priority_queue One ;
Data_type weight ;
int n = 600 ;
srand( time( NULL ) ) ;
for( int i = 1 ; i <= n ; ++i ){
weight = rand() % 100 + 1 ;
One.push( weight ) ;
}
while( !One.empty() ){
cout << One.top() << " " ;
One.pop() ;
}
cout << endl ;
return 0 ;
}
SCU 3369 自主编写最小堆 Prim
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std ;
#define INF 0x3f3f3f
typedef pair<int,int> P ;
int n , m , i , u , v , w ;
vector<P> One[10050] ;
int dis[10050] , C[10050] , book[10050] ;
struct Pair{
int dis , u ;
Pair(){}
Pair( int _dis , int _u ){
dis = _dis , u = _u ;
}
} ;
class My_Priority_queue{// 优先级队列默认为小顶堆
private:
int n ; // 优先级队列当前的元素个数
int Max_size ;
Pair **a ; // 数据指针, 顺序表
public:
My_Priority_queue( int _Max_size ) ; // 构造函数
~My_Priority_queue() ; // 析构函数
void push( Pair *weight ) ; // 往优先级队列中 push 数据
void pop() ; // pop 栈顶
Pair *top() ; // 访问栈顶元素
bool empty() ; // 判断栈是否为空
void Shift_down( int u ) ; // 递归 堆向下调整
} ;
My_Priority_queue::My_Priority_queue( int _Max_size ){
n = 0 ;
Max_size = _Max_size ;
a = new Pair*[3*Max_size] ;
for( int i = 0 ; i < 3*Max_size ; ++i )
a[i] = NULL ;
}
My_Priority_queue::~My_Priority_queue(){
for( int i = 0 ; i < 3*Max_size ; ++i )
a[i] = NULL ;
if( a ) delete [] a ;
}
void My_Priority_queue::push( Pair *weight ){
a[++n] = weight ; // push 压入的新元素放在末尾
int parent = n >> 1 , k = n ; // 因为前面的都是小顶堆
while( parent ){
if( a[k]->dis < a[parent]->dis )
swap( a[k] , a[parent] ) ;
k = parent ;
parent /= 2 ; // 从下向上调整, 只要和父亲相比
}
}
void My_Priority_queue::pop(){
if( empty() ) return ;
swap( a[1] , a[n--] ) ; // 把最后一个元素交换到堆顶, 堆大小 -1
Shift_down( 1 ) ; // 从堆顶开始向下调整
}
Pair *My_Priority_queue::top(){ // 取堆顶元素 , 优先级队列中最小的元素
return a[1] ;
}
bool My_Priority_queue::empty(){ // 判断优先级队列 ( 堆 ) 是否为空
return n < 1 ;
}
void My_Priority_queue::Shift_down( int u ){
int ans = u ;
if( 2*u <= n && a[2*u]->dis < a[ans]->dis ) // 比较左孩子
ans = 2*u ;
if( 2*u+1 <= n && a[2*u+1]->dis < a[ans]->dis ) // 比较右孩子
ans = 2*u+1 ;
if( ans != u ) // 最小的元素 a[ans] 在两个孩子当中
swap( a[ans] , a[u] ) , Shift_down( ans ) ; // 交换 , 继续向下调整
}
void Prim(){
memset( dis , INF , sizeof( dis ) ) ;
memset( book , 0 , sizeof( book ) ) ;
int ans = 0 , u , v , w ;
My_Priority_queue Q( n ) ;
Pair *cur = new Pair( dis[1] = 0 , 1 ) ;
Q.push( cur ) ;
while( !Q.empty() ){
Pair *top = Q.top() ;
Q.pop() ;
u = top->u ;
if( book[u] )
continue ;
book[u] = 1 ;
ans += top->dis ;
for( i = 0 ; i < (int)One[u].size() ; ++i ){
v = One[u][i].first , w = One[u][i].second ;
if( !book[v] && dis[v] > w ){
Pair *t = new Pair( dis[v] = w , v ) ;
Q.push( t ) ;
}
}
}
printf( "%d\n" , ans+*min_element( C+1 , C+n+1 ) ) ;
}
int main(){
while( ~scanf( "%d%d" , &n , &m ) ){
for( i = 1 ; i <= n ; ++i )
scanf( "%d" , &C[i] ) , One[i].clear() ;
for( i = 1 ; i <= m ; ++i ){
scanf( "%d%d%d" , &u , &v , &w ) ;
w = 2*w + C[u] + C[v] ;
One[u].push_back( P( v , w ) ) ;
One[v].push_back( P( u , w ) ) ;
}
Prim() ;
}
return 0 ;
}
SCU 3365 Disjkstra ( LCA 被我用 Disjkstra 做了, haha )
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std ;
#define INF 0x3f3f3f
typedef pair<int,int> P ;
int N , Q ;
vector<P> One[1001] ;
int dp[1001][1001] ;
int dis[1001] ;
struct Pair{
int dis , u ;
Pair(){}
Pair( int _dis , int _u ){
dis = _dis , u = _u ;
}
} ;
class My_Priority_queue{// 优先级队列默认为小顶堆
private:
int n ; // 优先级队列当前的元素个数
int Max_size ;
Pair **a ; // 数据指针, 顺序表
public:
My_Priority_queue( int _Max_size ) ; // 构造函数
~My_Priority_queue() ; // 析构函数
void push( Pair *weight ) ; // 往优先级队列中 push 数据
void pop() ; // pop 栈顶
Pair *top() ; // 访问栈顶元素
bool empty() ; // 判断栈是否为空
void Shift_down( int u ) ; // 递归 堆向下调整
} ;
My_Priority_queue::My_Priority_queue( int _Max_size ){
n = 0 ;
Max_size = _Max_size ;
a = new Pair*[3*Max_size] ;
for( int i = 0 ; i < 3*Max_size ; ++i )
a[i] = NULL ;
}
My_Priority_queue::~My_Priority_queue(){
for( int i = 0 ; i < 3*Max_size ; ++i )
a[i] = NULL ;
if( a ) delete [] a ;
}
void My_Priority_queue::push( Pair *weight ){
a[++n] = weight ; // push 压入的新元素放在末尾
int parent = n >> 1 , k = n ; // 因为前面的都是小顶堆
while( parent ){
if( a[k]->dis < a[parent]->dis )
swap( a[k] , a[parent] ) ;
k = parent ;
parent /= 2 ; // 从下向上调整, 只要和父亲相比
}
}
void My_Priority_queue::pop(){
if( empty() ) return ;
swap( a[1] , a[n--] ) ; // 把最后一个元素交换到堆顶, 堆大小 -1
Shift_down( 1 ) ; // 从堆顶开始向下调整
}
Pair *My_Priority_queue::top(){ // 取堆顶元素 , 优先级队列中最小的元素
return a[1] ;
}
bool My_Priority_queue::empty(){ // 判断优先级队列 ( 堆 ) 是否为空
return n < 1 ;
}
void My_Priority_queue::Shift_down( int u ){
int ans = u ;
if( 2*u <= n && a[2*u]->dis < a[ans]->dis ) // 比较左孩子
ans = 2*u ;
if( 2*u+1 <= n && a[2*u+1]->dis < a[ans]->dis ) // 比较右孩子
ans = 2*u+1 ;
if( ans != u ) // 最小的元素 a[ans] 在两个孩子当中
swap( a[ans] , a[u] ) , Shift_down( ans ) ; // 交换 , 继续向下调整
}
int Dijkstra( int src , int des ){
int i , u , v , w ;
memset( dis , INF , sizeof( dis ) ) ;
My_Priority_queue Q( N ) ;
Pair *cur = new Pair( dis[src] = 0 , src ) ;
Q.push( cur ) ;
while( !Q.empty() ){
Pair *top = Q.top() ;
Q.pop() ;
u = top->u ;
if( dis[u] < top->dis )
continue ;
for( i = 0 ; i < (int)One[u].size() ; ++i ){
v = One[u][i].first , w = One[u][i].second ;
if( dis[v] > dis[u] + w ){
Pair *t = new Pair( dis[v] = dis[u] + w , v ) ;
Q.push( t ) ;
}
}
}
for( i = 1 ; i <= N ; ++i )
dp[src][i] = dp[i][src] = dis[i] ;
return dis[des] ;
}
int main(){
int i , u , v , w ;
while( ~scanf( "%d%d" , &N , &Q ) ){
for( i = 1 ; i <= N ; ++i )
One[i].clear() ;
for( i = 1 ; i <= N-1 ; ++i ){
scanf( "%d%d%d" , &u , &v , &w ) ;
One[u].push_back( P( v , w ) ) ;
One[v].push_back( P( u , w ) ) ;
}
memset( dp , 0 , sizeof( dp ) ) ;
while( Q-- ){
scanf( "%d%d" , &u , &v ) ;
printf( "%d\n" , dp[u][v] ? dp[u][v] : Dijkstra( u , v ) ) ;
}
}
return 0 ;
}