[SDOI2010]魔法豬學院(Astar K短路模板)

更新:洛谷更新數據後有一個點會TLE

題目描述

題目太長了,大致說一下大意

有n個點,m條路,e(浮點型)的流量,接下來給定一個有向圖

問從1到n最多有幾種路線可以使權值之和小於e

思路

顯然,爲了使答案最大,我們一定要使每次的權值都儘可能的小

所以這就是一個K短路問題了(在k條路的時候正好小於等於e)

單純的K短路就是記錄每個點經過的次數

如果最後一個點走過k遍就是它的K短路了

下面的很多代碼是爲了優化,如果想看單純的K短路算法請看別的blog

首先SPFA先找出終點到每個點的最短距離(要先建反向圖)

A_star的估價函數就是當前距離加上這個點到終點的最短距離

(很好證明吧因爲這個點到終點最短最短就是上面這東西了)

然後我們可以對這個f(x)進行優先隊列的優化 不知道f(x)是什麼東西去看看A*算法吧

可能還是說的不是很清楚,還不懂的就直接看代碼吧

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int g,n,m,head[5005],tail[5005],ans;
double d[5005],e;
struct node{
    int from,to,next;
    double e;
}l[200005],lu[200005];
struct data{
    int d;
    double g,f;
    bool operator < (const data &a) const {
        if(f>a.f)return 1;return 0;
    }//運算符重載堆優化 
}zz,mm;
void add(int x,int y,double z)
{
    g++;l[g].next=head[x],head[x]=g;
    l[g].from=x,l[g].to=y,l[g].e=z;

    lu[g].next=tail[y],tail[y]=g;
    lu[g].from=y,lu[g].to=x,lu[g].e=z;
}//建正向圖的同時建反響圖 
int read()
{
    int z=0,f=1;
    char k=getchar();
    while(k<'0'||k>'9')  {if(k=='-')f=-1;k=getchar();}
    while(k>='0'&&k<='9'){z=(z<<3)+(z<<1)+k-'0';k=getchar();}
    return z*f;
}//讀優 
queue<int>p;//優化SPFA 
void spfa()
{
    int bj[5005]={0};
    for(int i=1;i<n;i++)d[i]=0x7fffffff;
    p.push(n);
    while(!p.empty())
    {
        int u=p.front();p.pop();
        for(int i=tail[u];i;i=lu[i].next)
        {
            int v=lu[i].to;
            if(d[u]+lu[i].e<d[v])
            {
                d[v]=d[u]+lu[i].e;
                if(!bj[v])bj[v]=1,p.push(v);
            }
        }
        bj[u]=0;
    }
}
int time[5005];//記錄進入次數 
priority_queue<data>q;//堆優化 
void A_star(int kk)
{
    zz.d=1,zz.g=0,zz.f=0;
    q.push(zz);
    while(!q.empty())
    {
        zz=q.top();q.pop();
        if(zz.f>e) return;
        int u=zz.d;
        time[u]++;
        if(u==n)
        {
            e-=zz.f;
            if(e<=0)return;//優化 
            ans++;continue;
        }
        if(time[u]>kk) continue;//優化 因爲kk次數之後的到達都不可能是答案的 
        for(int i=head[u];i;i=l[i].next)
        {
            mm.d=l[i].to,mm.g=zz.g+l[i].e,mm.f=mm.g+d[l[i].to];//A_star 
            q.push(mm);
        }
    }
}
int main()
{
    n=read(),m=read(),scanf("%lf",&e);
    for(int i=1;i<=m;i++)
    {
        int x,y;double z;
        x=read(),y=read(),scanf("%lf",&z);
        add(x,y,z);
    }
    spfa(),A_star(e/d[1]+1);
    printf("%d\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章