题意 : 求一张有向图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的算法, 但我不会, 下次补齐。:(