题目链接:http://poj.org/problem?id=2449
题意:很直接,求第k短路。
思路:没什么思路。参考了网上的资料学习了一波,对链式前向星的了解不够深刻,以前写Dijsktra为了简单粗暴直接用了邻接链表存储图,现在用了链式前向星就不会呃呃呃,毕竟too navie,这也是到现在做的第二个A*的题目,主要目的还是熟悉一下A*算法吧。
长路漫漫~
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <list>
#include <set>
//#define ONLINE_JUDGE
#define eps 1e-6
#define INF 0x7fffffff //INT_MAX
#define inf 0x3f3f3f3f //int??????????????????
#define FOR(i,a) for((i)=0;i<(a);(i)++) //[i,a);
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
#define MEM3(a) memset(a,0x3f,sizeof(a))
#define MEMS(a) memset(a,'\0',sizeof(a))
#define LL __int64
const double PI = acos(-1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
using namespace std;
template<class T>
T Mint(T a, T b, T c) {
if (a>b) {
if (c>b)
return b;
return c;
}
if (c>a)
return a;
return c;
}
template<class T>
T Maxt(T a, T b, T c) {
if (a>b) {
if (c>a)
return c;
return a;
}
else if (c > b)
return c;
return b;
}
const int Maxn=100010;
const int maxn=1005;
int T,n,m;
int head[maxn],tail[maxn];//head[i]表示以i为起点的第一条边存储的位置
int vis[maxn],dis[maxn];
int e;
int src,des,k;
struct node{
int to;//edge[i].to表示第i条边的终点
int w;//edge[i].w为边权值
int next;//edge[i].next表示与第i条边同起点的下一条边的存储位置
}edge[2*Maxn];
struct data{
int to;
int g,h;//启发式函数f[n]=g[n]+h[n],g[n]表示从初始节点到任意节点n的代价,h[n]表示从节点n到目标点的启发式评估代价
bool operator < (const data &a) const{//优先队列重载运算符
return a.g+a.h<g+h;
}
};
void addEdge(int u,int v,int w){
edge[e].to=v,edge[e].w=w,edge[e].next=head[u],head[u]=e++;//添加正向边
edge[e].to=u,edge[e].w=w,edge[e].next=tail[v],tail[v]=e++;//添加反向边
}
void Dijsktra(){//计算出从终点到各个节点的距离,用于启发式函数
MEM1(vis);
MEM3(dis);
dis[des]=0;
for2(i,1,n){
int pos=-1,min=inf;
for2(j,1,n){//找出此时离终点最近的点,这里可以考虑用堆优化
if(!vis[j]&&min>dis[j])
min=dis[pos=j];
}
if(pos==-1) break;
vis[pos]=1;
for(int u=tail[pos];u!=-1;u=edge[u].next){//更新各个节点到终点的距离
int v=edge[u].to;
if(!vis[v]&&dis[v]>dis[pos]+edge[u].w)
dis[v]=dis[pos]+edge[u].w;
}
}
}
int Astar(){
priority_queue<data>q;//优先队列维护启发式函数f[n]
data cur,nxt;
int cnt[maxn];//记录各个点访问次数
MEM1(cnt);
cur.to=src,cur.g=0,cur.h=dis[src];//初始化源点
q.push(cur);
while(!q.empty()){
cur=q.top();
q.pop();
cnt[cur.to]++;
if(cnt[cur.to]>k) continue;//若该节点扩展次数大于k次,就没必要继续扩展
if(cnt[des]==k) return cur.g;//若找到第k短路,则返回当前值
for(int u=head[cur.to];u!=-1;u=edge[u].next){
int v=edge[u].to;
nxt.to=v;
nxt.g=cur.g+edge[u].w;
nxt.h=dis[v];
q.push(nxt);
}
}
return -1;//若不存在则返回-1
}
int main(){
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
#endif
while(~sfd(n,m)){
e=0;
MEM2(head);
MEM2(tail);
int a,b,c;
while(m--){
sft(a,b,c);
addEdge(a,b,c);
}
sft(src,des,k);
if(src==des) k++;//若起点和终点重合,k需要+1
Dijsktra();
int ans=Astar();
pf(ans);
}
return 0;
}