http://poj.org/problem?id=2449

第k短路 刚开始上网找了分标准解法 没看懂呀 汗   然后看别人都用了A*算法  我也不知道是

什么东西

如果我们用队列枚举的话 当第k次出现终点 则这时就是到终点的第k短路 

但是这样队列是承受不住的 因为数据会太多

对于这道题 思路好像基本上就是

构造一个函数 f(i)=g(i)+h(i)    g为出发点到i的最短距离 h为终点到i的最短距离

f 为他们的和但每次取f最小的点进行更新

直到终点出现第k次 既为答案

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string.h>

using namespace std;

const int N=1001;
const int M=1000005;
const int MAX=0x5fffffff;
struct ss
{
    int x,y;
    int d;
}mem[M];
int head[N];
struct to
{
    int j,k;
    int next;
}side[M];
struct node
{
    int f,g;
    int x;
    bool operator <(const node a) const
    {
        if(a.f==f)
        return a.g<g;
        return a.f<f;
    }
};
priority_queue< node >str;
void build(int x,int i)
{
    side[i].next=head[x];
    head[x]=i;
}
int dist[N];
int had[N];
void spfa(int s,int n)
{
    queue<int>st;
    memset(had,0,sizeof(had));
    for(int i=1;i<=n;++i)
    dist[i]=MAX;
    dist[s]=0;
    had[s]=1;
    st.push(s);
    while(!st.empty())//求到终点最短距离
    {
        int x=st.front();
        st.pop();
        had[x]=0;
        int t=head[x];
        while(t!=-1)
        {
            if(dist[side[t].j]>dist[x]+side[t].k)
            {
                dist[side[t].j]=dist[x]+side[t].k;
                if(!had[side[t].j])
                {
                    st.push(side[t].j);
                    had[side[t].j]=1;
                }
            }
            t=side[t].next;
        }
    }
}
int Astar(int S,int T,int k,int n)
{
    if(dist[S]==MAX)
    return -1;
    if(S==T)//这里坑嗲
    ++k;
    while(!str.empty())
    str.pop();
    node k1,k2;
    k1.f=dist[S];
    k1.x=S;
    k1.g=0;
    str.push(k1);//用优先队列实现 
    memset(had,0,sizeof(had));
    while(!str.empty())
    {
        k1=str.top();//每次取f最小
        str.pop();
        ++had[k1.x];
        if(had[T]==k)//不断寻找 直到终点第 k 次出现 就是第k短路
        return k1.g;
        if(had[k1.x]>k)
        continue;
        int t=head[k1.x];
        while(t!=-1)
        {
            k2.x=side[t].j;
            if(dist[k2.x]==MAX)
            {
                t=side[t].next;continue;
            }
            k2.g=k1.g+side[t].k;
            k2.f=k2.g+dist[k2.x];
            str.push(k2);
            t=side[t].next;
        }
    }
    return -1;
}
int main()
{
    freopen("data.txt","r",stdin);
    int n,m,k,S,T;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;++i)
        {
            scanf("%d %d %d",&mem[i].x,&mem[i].y,&mem[i].d);
            side[i].j=mem[i].x;
            side[i].k=mem[i].d;//建反向图
            build(mem[i].y,i);
        }
        scanf("%d %d %d",&S,&T,&k);
        spfa(T,n);//求到终点 最短路
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;++i)
        {
            side[i].j=mem[i].y;
            build(mem[i].x,i);//建正向边
        }
        printf("%d\n",Astar(S,T,k,n));//A×
    }
    return 0;
}

  

posted on 2012-08-07 09:37  夜->  阅读(151)  评论(0编辑  收藏  举报