POJ_3159_差分约束+heap+dijsktra

//============================================================================
// Name        : POJ_3159.cpp
// Author      : tiger
// Version     :
// Copyright   : Your copyright notice
// Description : 今天一下学习了 差分约束+heap+dijsktra呵呵 ,代码是别人的但做了一
//                些优化
//                原代码g++ TLE; c++ 1500MS
//                优化后 g++ 2784K 610MS ; c++  2264K 594MS
//============================================================================

#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
#define SIZE 30005
#define MAX 1000000000
struct Node
{
    int id,val;
    Node *next;
}node[SIZE];
//----
Node stack[150005];
int ret;
//----
struct Heap
{
    int id,val;
}heap[2*SIZE];

int n,m;
void insert(int a,int b,int val)
{
    //-----
    Node *p = stack + ret++;
    //    Node *p = new Node;
    p->id = a;
    p->val = val;
    p->next = node[b].next;
    node[b].next = p;
}
int len[SIZE],tail;
bool visit[SIZE];
void heappush(int k,int val)     // k是节点编号(内容),val是堆节点的权值
{
    int t,tt;
    heap[++tail].val = val;       //先插入到堆尾
    heap[tail].id = k;
    tt = tail;
    while((t = tt/2) >= 1)
    {
        if(heap[t].val > heap[tt].val)
        {
            /*
            temp = heap[t].id;
            heap[t].id = heap[tt].id;
            heap[tt].id = temp;
            */
            //---------
            heap[t].id ^= heap[tt].id;
            heap[tt].id ^= heap[t].id;
            heap[t].id ^= heap[tt].id;

            heap[t].val ^= heap[tt].val;
            heap[tt].val ^= heap[t].val;
            heap[t].val ^= heap[tt].val;

            /*
            temp = heap[t].val;
            heap[t].val = heap[tt].val;
            heap[tt].val = temp;
            */

            tt = t;
        }
        else break;
    }
}
int heappop()
{
    int t,tt,re;
    re = heap[1].id;
    heap[1].id = heap[tail].id;
    heap[1].val = heap[tail--].val;
    t = 1;
    while((tt = t*2) <= tail)
    {
        if(tt+1 <= tail && heap[tt+1].val < heap[tt].val)     //选择左右孩子里比较小的替换
            tt++;
        if(heap[tt].val < heap[t].val)
        {
            /*
            temp = heap[t].id;
            heap[t].id = heap[tt].id;
            heap[tt].id = temp;
            temp = heap[t].val;
            heap[t].val = heap[tt].val;
            heap[tt].val = temp;
            */

            heap[t].id ^= heap[tt].id;
            heap[tt].id ^= heap[t].id;
            heap[t].id ^= heap[tt].id;

            heap[t].val ^= heap[tt].val;
            heap[tt].val ^= heap[t].val;
            heap[t].val ^= heap[tt].val;
            t = tt;
        }
        else break;
    }
    return re;
}
int answer(int s,int t)
{
    int i,j;
    for(i = 1; i <= n; i++)
        len[i] = MAX;
    Node *p;
    p = node[s].next;
    while(p)
    {
        len[p->id] = p->val;
        p = p->next;
    }
    tail = 0;
    for(i = 1; i <= n; i++)
        heappush(i,len[i]);
    visit[s] = 1;
    int e;
    for(j = 1; j < n; j++)
    {
        e = heappop();
        while(visit[e])
            e = heappop();
        if(len[e] == MAX || e == t)
            break;
        visit[e] = 1;
        p = node[e].next;
        while(p)            //node[]是邻接表的表头,数组每个元素指向的链表存放的是该项与表头的距离
        {
            if(!visit[p->id]&&len[p->id]>len[e]+p->val)    //p->val是e节点到p->id节点的距离
            {
                len[p->id] = len[e]+p->val;
                heappush(p->id,len[p->id]);
            }
            p = p->next;
        }
    }
    return len[t];
}
int main()
{
    ret = 0;
    freopen("in","r",stdin);
    int i,a,b,val;
    scanf("%d%d",&n,&m);
    for(i = 0; i < m; i++)
    {
        scanf("%d%d%d",&a,&b,&val);
        insert(a,b,val);
    }
    printf("%d/n",answer(n,1));
    return 0;
}

//原代码转自:http://blog.csdn.net/cugbliang/archive/2008/07/15/2656506.aspx
算法是实现单源最短路径的一种算法,一般情况下用邻接矩阵表示图,然后从小到大找到各个点离源点的距离,不过用邻接矩阵对于比较稀疏的图(顶点较多,但边较少)是比较浪费的,
对于这种情况邻接表就比较适合了,而且只需遍历一个数组指针头指向的链表就可以找到或告诉你没有路径可循。
而对于Dijstra算法,由于每次都需要扩充当前最短的路径(含有贪心的思想),所以存放路径的数据结构显得很重要,
单纯的数组、链表在遍历过程中的时间复杂度有目共睹,所以使用 O(logN)的堆就是一个不错的选择,
数据结构中的堆有别于内存管理中的堆(关于内存中的堆内容,详见我的另一篇blog:堆栈与C/C++)
数据结构中的堆:(我们提到的堆是最大堆)堆是一种特殊的二叉树,具备以下两种性质
1)每个节点的值都大于(或者都小于,称为最小堆)其子节点的值
2)树是完全平衡的,并且最后一层的树叶都在最左边
堆可以用一个数组表示,有如下性质:
heap[i]>=heap[2*i]    其中1<=i<=(n)/2
heap[i]>=heap[2*i+1]    其中1<=i<=(n-1)/2
这样查找的时间复杂度就是O(1),无论是插入、删除的时间复杂度都是O(logN),
在 Dijstra算法中如果使用邻接矩阵,时间复杂度是O(N^2);
而如果使用堆+邻接表,时间复杂度为O(NlongN)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值