您的位置:首页 > 其它

[POJ]2449. Remmarguts' Date

2015-10-12 14:33 357 查看
这道题是求一个有向图上的第k短路。这时,可以采用A*搜索,也就是启发式搜索的办法。所谓启发式搜索,是在搜索的时候设置一个启发式函数,以此来确定搜索的顺序,,从而减少无用功。

本题中,启发函数为f(x) = distance_traveled(x) + distance_remaining(x). 前者为搜索到x点时已经走过的路程,后者为到终点还剩的路程。可以在A*搜索之前把后者先全部预处理出来以节省时间。在A*搜索时可以用C++的priority_queue来做,注意这个优先队列是把大的数据放在前面的,所以自己在结构体中重载优先级的时候要注意把f(x)小的定义成大的。

P. S. 时隔两年多再写这个博客,有点感慨啊。。。

#include <cstdio>
#include <queue>
using namespace std;

struct Edge
{
int dt, c, next;
};

const int INF = 1000000;
int n, m, edgenum1, edgenum2, s, t, k, dis[2000], vis[2000], first1[2000], first2[2000];
Edge edge1[110000], edge2[110000];

struct a_star
{
int v, len;
bool operator < (const a_star &a) const
{
return len + dis[v] > a.len + dis[a.v];
}
};

void init()
{
edgenum1 = edgenum2 = 0;
for (int i = 1; i <= n; i++)
first1[i] = first2[i] = 0;
}

void add_edge1(int u, int v, int c)
{
edgenum1++;
edge1[edgenum1].next = first1[u];
edge1[edgenum1].dt = v;
edge1[edgenum1].c = c;
first1[u] = edgenum1;
}

void add_edge2(int u, int v, int c)
{
edgenum2++;
edge2[edgenum2].next = first2[u];
edge2[edgenum2].dt = v;
edge2[edgenum2].c = c;
first2[u] = edgenum1;
}

void dijk(int u)
{
int i, j, tmp;
for (i = 1; i <= n; i++)
{
vis[i] = 0;
dis[i] = INF;
}
dis[u] = 0;
for (i = 1; i <= n; i++)
{
int mini, minc = INF;
for (j = 1; j <= n; j++)
if (!vis[j] && dis[j] < minc)
{
minc = dis[j];
mini = j;
}
vis[mini] = 1;
tmp = first2[mini];
while (tmp)
{
int c = edge2[tmp].c, v = edge2[tmp].dt;
tmp = edge2[tmp].next;
if (vis[j] || dis[v] <= dis[mini] + c)
continue;
dis[v] = dis[mini] + c;
}
}
}

int solve()
{
if (s == t)
k++;
if (vis[s] == 0)
return -1;
for (int i = 1; i <= n; i++)
vis[i] = 0;
a_star n1;
priority_queue <a_star> q;
n1.v = s;
n1.len = 0;
q.push(n1);
while (!q.empty())
{
a_star head = q.top();
q.pop();
vis[head.v]++;
if (vis[t] == k)
return head.len;
if (vis[head.v] > k)
continue;
int tmp = first1[head.v];
while (tmp)
{
a_star n2;
n2.v = edge1[tmp].dt;
n2.len = edge1[tmp].c + head.len;
tmp = edge1[tmp].next;
q.push(n2);
}
}
return -1;
}

int main()
{
int u, v, c;
scanf("%d%d", &n, &m);
init();
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &u, &v, &c);
add_edge1(u, v, c);
add_edge2(v, u, c);
}
scanf("%d%d%d", &s, &t, &k);
dijk(t);
printf("%d\n", solve());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: