您的位置:首页 > 其它

POJ-2449 Remmarguts' Date

2015-10-22 12:04 246 查看
/************************************************
* Author        :somniloquy
* Created Time  :2015/10/22 9:26:14
************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

const int n_max = 1e3 + 5;
const int m_max = 1e5 + 5;
const int INF = 0x3fffffff;
int n, m, pos, s, t, k, ans;
int connect_1[n_max];       //正向连接
int connect_2[n_max];       //反向连接
int sign[n_max];
int dis[n_max];         //记录终点到各个点的最短路(即 h)
int cnt[n_max];         //记录所有的点的拓展次数(大于k 不继续拓展)
struct node
{
int Next;
int to;
int len;
} edge_1[m_max], edge_2[m_max]; //正向图 反向图
struct star
{
int data;
int g;          //实际花费
int h;          //估计值(即 dis[])
int f;          //g + h (经过该点再到终点的总花费)
bool operator < (const star Next) const
{
if(Next.f == f)
return Next.g < g;
else
return Next.f < f;  //总是先弹出f最小的
}
} Now, Next;

void init()         //初始化
{
memset(connect_1, -1, sizeof(connect_1));
memset(connect_2, -1, sizeof(connect_2));
memset(sign, 0, sizeof(sign));
fill(dis, dis + n_max, INF);
memset(cnt, 0, sizeof(cnt));
pos = 0;
}

void add_edge(node* edge, int* connect, int op, int ed, int len)    //加边
{
edge[pos].Next = connect[op];
connect[op] = pos;
edge[pos].to = ed;
edge[pos].len = len;
}

void SPFA(int src)          //利用反向图 从终点出发 计算出终点到每一点的最短距离(必须利用反向图,因为是单向边)
{
queue <int> process;
process.push(src);
sign[src] = 1;
dis[src] = 0;
while(!process.empty())
{
int this_op = process.front();
process.pop();
sign[this_op] = 0;
for(int i = connect_2[this_op]; i != -1; i = edge_2[i].Next)
{
int this_ed = edge_2[i].to;
int this_len = edge_2[i].len;
if(dis[this_op] + this_len < dis[this_ed])
{
dis[this_ed] = dis[this_op] + this_len;
if(!sign[this_ed])
{
process.push(this_ed);
sign[this_ed] = 1;
}
}
}
}
}

void A_star(int op, int ed, int rank)       //从起点出发 利用正向图 不断进行拓展
{
priority_queue <star> process;
Now.data = op;              //初始化第一个元素
Now.g = 0;
Now.h = dis[op];
Now.f = Now.g + Now.h;
process.push(Now);
while(!process.empty())
{
Now = process.top();
process.pop();
cnt[Now.data] ++;       //计数
if(cnt[Now.data] > rank)
continue;
if(cnt[ed] == rank)     //达到目标 ans赋值 弹出
{
ans = Now.g;
return;
}
for(int i = connect_1[Now.data]; i != -1; i = edge_1[i].Next)       //强制走到这个点 并计算总花费f
{
Next.data = edge_1[i].to;
Next.g = Now.g + edge_1[i].len;
Next.h = dis[Next.data];
Next.f = Next.g + Next.h;
process.push(Next);
}
}
}

int main(void)
{
while(~scanf("%d %d", & n, & m))
{
init();
int a, b, t;
for(int i = 0; i < m; i ++)
{
scanf("%d %d %d", & a, & b, & t);
add_edge(edge_1, connect_1, a, b, t);       //正向建图 A_star用
add_edge(edge_2, connect_2, b, a, t);       //反向建图 SPFA用
pos ++;
}
scanf("%d %d %d", & s, & t, & k);
if(s == t)      //题目要求 必须走一条路 当s==t 最短路不应该是0 所以要在k的基础上+1
k ++;
SPFA(t);        //终点做起点
ans = -1;
A_star(s, t, k);    //A*算法
printf("%d\n", ans);
}
return 0;
}


题目

输入n m。表示点的个数 边的条数(单向)。

接下来的m行 输入 a b t。表示 a到b的花费t。(a b两个顶点 t边长)

输入 s t k。求s到t的第k短路径长度。

不存在输出-1。

必须走一条路。

题解:

算是一道A*求最短路的模板题了…

我写这道题的最大的错误是没有建反向图。因为是单向边,要从终点出发,要完全反向行走,才能计算终点到各点的最短距离。(因为上一道题是双向边..所以没考虑过..)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: