poj 2449 Remmarguts' Date(A*+Dijsktra 求第K短路)

题目链接: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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值