POJ 2449Remmarguts' Date (A* 求K短路)

题目链接

题意 : 求一张有向图S->T的K短路。

思路 : 经典题目。 K短路最简单并且最暴力的方法是从起始点S爆搜下去, 把到达的x的距离d[x]不停的加入到一个优先队列中去, 最后然后每次取出最短距离节点u,然后cnt[u]++一直到到达了u = T && cnt[u] = k结束搜索。 这个方法复杂度似乎是O(M*K),对于这道题目是超时或者爆内存的 = = 。

网上看了下比较好也比较容易写的方法是A*: 评估函数f(x) = g(x) + h(x)   ( f(x) 小的优先级高, 先搜),g(x)表示的是从S到x现在搜索到的距离,不断用最短的f(x),更新, h(x)表示从x到T的最短距离(建立反向边用Dijkstra或者spfa算法预处理出来),这样利用A*优化搜索可以AC这道题目。

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       

using namespace std;

const int maxn = 100005;
const int INF = 12842184;

struct Dist{
    int d, x;
    Dist(){}
    Dist(int a, int b) : d(a), x(b){}
    bool operator < (const Dist &cmp)const {
        return d > cmp.d;
    }
};

struct astar{
    int g, h, x;
    astar(){}
    astar(int a, int b, int c) : g(a), h(b), x(c){}
    bool operator < (const astar &cmp)const {
        return g + h > cmp.g + cmp.h;
    }
};

struct Edge{
    int to, c, next;
}edge[2][maxn];

int n, m, k, E1, E2, sx, ex;
int d[maxn], vis[maxn], cnt[maxn], head[2][maxn];

void init(){
    E1 = 0, E2 = 0;
    memset(head, -1, sizeof(head));
}

void add_edge(int u, int to, int c, int &E, Edge *edge, int *head){
   edge[E].to = to;
   edge[E].c = c;
   edge[E].next = head[u];
   head[u] = E++;
}

void Dijkstra(){
    fill(d+1, d+n+1, INF); d[ex] = 0;
    memset(vis, 0, sizeof(vis));
    priority_queue
       
       
         q; q.push(Dist(d[ex], ex)); while (!q.empty()){ Dist tmp = q.top(); q.pop(); int u = tmp.x; if (vis[u])continue; vis[u] = 1; for (int i = head[1][u]; i != -1; i = edge[1][i].next){ int to = edge[1][i].to, c = edge[1][i].c; if (d[to] > d[u] + c){ d[to] = d[u] + c; q.push(Dist(d[to], to)); } } } return ; } int A_star(){ Dijkstra(); if (sx == ex)k++;// 这是一个trick priority_queue 
        
          q; memset(cnt, 0, sizeof(cnt)); q.push(astar(0, d[sx], sx)); while (!q.empty()){ astar tmp = q.top(); q.pop(); int u = tmp.x; cnt[u]++; if (cnt[u] > k)continue; if (u == ex && cnt[u] == k)return tmp.g; for (int i = head[0][u]; i != -1; i = edge[0][i].next){ int to = edge[0][i].to, c = edge[0][i].c; q.push(astar(tmp.g+c, d[to], to)); } } return -1; } int main(){ scanf("%d%d", &n, &m); init(); while (m--){ int a, b, c; scanf("%d%d%d", &a, &b, &c); add_edge(a, b, c, E1, edge[0], head[0]); add_edge(b, a, c, E2, edge[1], head[1]); } scanf("%d%d%d", &sx, &ex, &k); printf("%d\n", A_star()); return 0; } 
         
       
      
      
     
     
    
    
   
   






PS  :虽然AC了但是这种方法给我的感觉还是很暴力(但是据说一般都是可以做了的), 汗....    k - 短路问题网上还有一种叫做Yen的算法, 但我不会, 下次补齐。:(


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值