pku2449[第k短路]

打算开始做题了。在这样耗散下去实在是不好意思跟别人讲弄过ACM。

这是一道最基本的第k短路的题,很久没有做过A*的题几乎都忘了原理。还有就是这次写个dij都一直手贱。


思路:

1.A*:现在对于A*的理解是:f(x)=h(x)+g(x).其中h(x)是从起始点到当前节点的花费,g(x)是估价函数,估计的是当前节点x到目的节点的花费。这个估计值一定要比实际值小,对于A*的不同就是估价函数的选取不同,这道题用的是最短路(曾经我用过两点间直线最短,还有就是两点间的x距离和y距离之和),其实,我这次再看了一遍资料觉得这个很像BFS,BFS就是把访问过的放到优先队列,只是那里g(x)是为0,也就是找到当前代价最小的继续访问,而A*是找到当前f(x)最小的进行访问。

2.对于k短路来讲也就是在A*搜索的过程中,目的节点出队列的次数为第k次。第一次出队列肯定是最短路。

3.这题的坑:重边,起始点等于目的点(需要判断如果相等那么k++,因为A*会算0为最短路)


代码:

#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
using namespace std;
int ed[1010][1010];
int h[1010],g[1010],dis[1010];
int inf=10000001;
struct node{
    int v,w;
};
vector<node>edt[1010];
struct cnode{
    int u;
    int len;
    cnode(int uu,int ww):u(uu),len(ww){}
    friend bool operator < (cnode a,cnode b){
        return a.len+dis[a.u]>b.len+dis[b.u];
    }
};
void dij(int sta,int n){
    int flag[1010];
    for(int i=0;i<=1009;i++){
        dis[i]=inf;
        flag[i]=0;
    }
    dis[sta]=0;
    int u=sta;
    flag[u]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(dis[u]+ed[u][j]<dis[j]){
                dis[j]=dis[u]+ed[u][j];
            }
        }
        int max=inf;
        for(int j=1;j<=n;j++){
            if(dis[j]<max && !flag[j]){
                u=j;
                max=dis[j];
            }
        }
        if(u!=inf)
            flag[u]=1;
    }
}
int tot[1010];
int a_star(int s,int n,int k,int e){
    if(dis[s]==inf) return -1;
    priority_queue<cnode>que;
    memset(tot,0,sizeof(tot));
    que.push(cnode(s,0));
    if(s==e)k++;
    while(!que.empty()){
        cnode cnt=que.top();
        que.pop();
        tot[cnt.u]++;
        if(tot[cnt.u]==k && cnt.u==e) return cnt.len;
        for(int i=0;i<edt[cnt.u].size();i++){
            que.push(cnode(edt[cnt.u][i].v,cnt.len+edt[cnt.u][i].w));
        }
    }
    return -1;
}
main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=-1){
        int a,b,t,s,e,k;
        for(int i=0;i<=n;i++){
            for(int j=0;j<=n;j++){
                ed[i][j]=inf;
            }
            edt[i].clear();
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&t);
            if(t<ed[b][a])
            ed[b][a]=t;
            node nnode;
            nnode.v=b;
            nnode.w=t;
            edt[a].push_back(nnode);
        }
        scanf("%d%d%d",&s,&e,&k);
        dij(e,n);
        printf("%d\n",a_star(s,n,k,e));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值