优先队列和堆 实战:HDU1242

什么叫优先队列呢,能完成以下任务的就叫做优先队列:

·插入一个数值

·取出最小的数值(获取数值,并且删除)

实现优先队列,应该使用二叉树完成,是一种叫二叉堆的数据结构(binary heap)

二叉堆分为两种,最小堆和最大堆。最小堆是父节点的键值总是小于等于子节点的键值。最大堆是父节点的键值总是大于等于子节点的键值。

可以将二叉堆看成数组的形式。

代码:

// 模拟最小堆
// 最小堆是二叉堆的一种,其特点是父节点的键值总是小于或者等于子节点。
// 实现细节:
//          push:向堆中插入数据时,首先在堆的末尾插入数据,然后不断向上提升,直到没有大小颠倒时。
//          pop:从堆中删除最小值时首先把最后一个值复制到根节点上,并且删除最后一个数值。然后不断向下交换
//               直到没有大小颠倒为止。在向下交换过程中,如果有两个子儿子都小于自己,就选择较小的
#include 
using namespace std;
const int MAX_N = 1005;
int heap[MAX_N], sz = 0;
void push(int x);
void display();
int pop();
int main()
{
    // 测试
    int x;
    int cmd;
    do
    {
        cout << "请输入命令:1.push\t2.pop\t3.display\t0.quit\n";
        cin >> cmd;
        switch(cmd)
        {
        case 1:
            cout << "Input X:";
            cin >> x;
            push(x);
            break;
        case 2:
            x = pop();
            cout << x << "已取出!\n";
            break;
        case 3:
            display();
            break;
        }
    }while(cmd);

    return 0;
}

void push(int x)
{
    // i是要插入节点的下标
    int i = sz++;
    while(i > 0)
    {
        // p为父亲节点的下标
        int p = (i - 1) / 2;
        // 如果父亲节点小于等于插入的值,则说明大小没有跌倒,可以退出
        if(heap[p] <= x)
            break;
        // 互换当前父亲节点与要插入的值
        heap[i] = heap[p];
        i = p;
    }

    heap[i] = x;
    cout << "数据插入成功!\n";
}

int pop()
{
    // 取出根节点
    int ret = heap[0];
    // 将最后一个节点的值提到根节点上
    int x = heap[--sz];
    int i = 0;
    while(i * 2 + 1 < sz)
    {
        // a,b为左右两个子节点的下标
        int a = 2 * i + 1, b = 2 * i + 2;
        // 去两个子节点中较小的值
        if(b < sz && heap[b] < heap[a])
            a = b;
        // 如果已经没有大小颠倒的话则退出循环
        if(heap[a] >= x)
            break;
        // 将父亲节点与子节点互换
        heap[i] = heap[a];
        i = a;
    }
    heap[i] = x;

    return ret;
}

void display()
{
    for(int i = 0; i < sz; i++)
        cout << heap[i] << "\t";
    cout << endl;
}

但是在c++的STL中已经包含了优先队列的高效实现——priority_queue,不过与上面的例子不一样的是每次取出数值都是最大值。

看一个简单的实例:

#include 
#include 
using namespace std;

int main()
{
	// 声明 
	priority_queue pque;
	
	// 插入元素 
	pque.push(3);
	pque.push(5);
	pque.push(1);
	
	// 不断循环直到为空为止
	while(!pque.empty())
	{
		// 获得最大值并且删除 
		cout << pque.top() << endl;
		pque.pop();
	} 
	
	return 0;
} 

用杭电的一题来实战一下吧

题目点击打开链接

题目的意思是和走迷宫找最短出口差不多,就是有一个天使(在地图上显示为a),你是天使的好基友(在地图上显示为r),为了拯救基友,你打算去劫狱,.代表路, #代表墙壁。每走一步就要花一个时间单位。监狱里当然会有很多狱警(在地图上显示为x)啦,但是基情使你充满力量,轻轻松松能杀死一个狱警,也只要一个时间单位好了。现在你要怎么做才能在最短的时间内救出好基友。

=_=

这题很明显就是使用BFS来做的。因为里面多了一个狱警,所以用队列的话就比较麻烦了,所以在这里使用优先队列。

因为优先队列默认是取出最大值的,所以首先要重载一下运算符,让优先取出最小值。

ac代码如下:

#include 
#include 
#include 
using namespace std;

const string fail = "Poor ANGEL has to stay in the prison all his life.";
const int INF = 1000005;
const int MAX_N = 205;
int N, M;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
char pic[MAX_N][MAX_N];
struct Node
{
    int x, y;
    int num;
    // 将优先队列每次取出最大值改为每次去最小值
    bool operator < (const Node &a) const
    {
        return num > a.num;
    }
}first, next;
int bfs();

int main()
{
    while(cin >> N >> M)
    {
        int i, j;
        for(i = 0; i < N; i++)
        {
            cin >> pic[i];
            for(j = 0; j < M; j++)
            {
                if(pic[i][j] == 'a')
                {
                    first.x = i;
                    first.y = j;
                    first.num = 0;
                    pic[i][j] = '#';
                }
            }
        }
        int ans = bfs();
        if(ans == INF)
            cout << fail << endl;
        else
            cout << ans << endl;
    }

    return 0;
}

int bfs()
{
    priority_queue que;
    que.push(first);
    while(que.size())
    {
        first = que.top();
        que.pop();
        for(int i = 0; i < 4; i++ )
        {
            next.x = first.x + dx[i];
            next.y = first.y + dy[i];
            if(next.x >= 0 && next.x < N && next.y >=0 && next.y < M && pic[next.x][next.y] != '#')
            {
                next.num = first.num;
                if(pic[next.x][next.y] == 'r')
                    return next.num + 1;
                else if(pic[next.x][next.y] == '.')
                    next.num += 1;
                else if(pic[next.x][next.y] == 'x')
                    next.num += 2;
                pic[next.x][next.y] = '#';
                que.push(next);
            }
        }
    }

    return INF;
}


你可能感兴趣的:(ACM,算法,数据结构,搜索)