【BZOJ3627】【JLOI2014】路径规划 分层图

题意:自己看,这有传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3627

注意:点的等待时长示意图为:

【BZOJ3627】【JLOI2014】路径规划 分层图_第1张图片

很清晰了吧?没事,不清晰就不清晰吧,反正公式给你了,这不是本题知识点,扒就行了。


题解:

    看到这题的数据范围,我们就想到了分层图,可是现在有两种需要分层的东西:剩余油量的限制,和经过红绿灯的限制。所以我们要搞掉其中一个,使题目转化成分层图。红绿灯限制很不好惹的样子,所以我们还是把剩余油量的限制搞掉吧。

    怎么搞掉油量的限制呢?我们可以把整个图缩成一个只有加油站的图,这样两加油站之间只要可以直接到达,就不用再管【剩余油量】了!当然,起点和终点也要算到加油站中,至于终点可能多加的一份【加油费用】,再删掉就好了~

    具体做法:很简单地说。。枚举每个加油站,看满油从它出发能跑到哪些点,然后建边(新图的边,点为加油站的图的边),而两点之间根据经过红绿灯的不同,所以可能有多条边。。再简单一点的说法就是——看下述代码!!

    好了,新图建好了,跑一遍水水的分层图吧。就是dist[i][j]表示到j时经过i个红绿灯的最短路径,至于若j有红灯时算不算上神马的就不用写得太拘束了,爱怎么写怎么写,题目到这里已经很水了。。


注意: 

    我们在预处理节点名称的时候不妨建一棵字典树,这样找起来会很快,代码也很好写。不然可能就需要写一发pq优化的nlogn最短路,哪个好写,自己想吧。另,如果想刷rank,这两个都得写!!!

    如果不会分层图的话,不妨看看这一篇:http://blog.csdn.net/vmurder/article/details/40075989

    好了,直接贴代码,写得比较清晰,只是因为代码量的缘故才会看着发晕。认真仔细一点很容易看懂(大不了你用样例数据手调一下我的代码!不信看不懂!)

(原题数据范围错了,n和m都应该是原来的2倍。)

/**************************************************************
    Problem: 3627
    User: 18357
    Language: C++
    Result: Accepted
    Time:716 ms
    Memory:69628 kb
****************************************************************/
 
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
#define M 20100
#define P 60
#define TT 80
#define eps 1e-7
#define inf 0x3f3f3f3f
using namespace std;
/*i won't tell you it's a trie. */
struct Trie
{
    int next[N*20][TT],cnt;
    int note[N*20],sign;
    char s[TT];
    inline int insert()
    {
        scanf("%s",s+1);
        int x=0,i,alp;
        for(i=1;s[i];i++)
        {
            alp=s[i]-'0';
            if(!next[x][alp])next[x][alp]=++cnt;
            x=next[x][alp];
        }
        if(!note[x])note[x]=++sign;
        return note[x];
    }
    inline int judge()
    {
        for(int i=1;s[i];i++)if(i>=5&&s[i]=='t'&&s[i-1]=='r'&&s[i-2]=='a'&&s[i-3]=='t'&&s[i-4]=='s')return 1;
        for(int i=1;s[i];i++)if(i>=3&&s[i]=='s'&&s[i-1]=='a'&&s[i-2]=='g')return 2;
        for(int i=1;s[i];i++)if(i>=3&&s[i]=='d'&&s[i-1]=='n'&&s[i-2]=='e')return 3;
        return 0;
    }
}trie;
/*for original graph or prespfa or the gas_station graph. */
struct KSD
{
    int u,v,next;
    double len;
}e[M<<1],E[15][P*P<<1];
int head[N],cnt;
void add(int u,int v,double len)
{
    cnt++;
    e[cnt].u=u;
    e[cnt].v=v;
    e[cnt].len=len;
    e[cnt].next=head[u];
    head[u]=cnt;
}
int HEAD[15][P],CNT[15];
void ADD(int light,int u,int v,double len)
{/*i feel sick for my code here, but i can't do anything. */
    CNT[light]++;
    E[light][CNT[light]].u=u;
    E[light][CNT[light]].v=v;
    E[light][CNT[light]].len=len;
    E[light][CNT[light]].next=HEAD[light][u];
    HEAD[light][u]=CNT[light];
}
struct Lux
{
    int x,y;
    Lux(int _x,int _y):x(_x),y(_y){}
    Lux(){}
};
queue<Lux>q;
double dist[15][N];
bool in[15][N];
/*for static code*/
int n,m,lig,gas,cost;
/*for each point*/
bool red[N];
int sta[N];
double ave[N];
int gas_station[N],num;
/*for temp input*/
char ttt[TT];
 
void prespfa(int S)
{/*build the direct combinations between the gas_stations. */
    while(!q.empty())q.pop();
    memset(dist,0x7f,sizeof(dist));
    int i,v,temp;
    dist[0][S]=0;
    in[0][S]=1;
    q.push(Lux(0,S));
    while(!q.empty())
    {
        Lux U=q.front();q.pop();in[U.x][U.y]=0;
        for(i=head[U.y];i;i=e[i].next)
        {
            v=e[i].v;
            temp=U.x+red[v];
            if(temp<=lig&&dist[U.x][U.y]+e[i].len+ave[v]<=gas&&dist[temp][v]>dist[U.x][U.y]+e[i].len+ave[v])
            {
                dist[temp][v]=dist[U.x][U.y]+e[i].len+ave[v];
                if(!in[temp][v])in[temp][v]=1,q.push(Lux(temp,v));
            }
        }
    }
}
double divspfa(int S,int T)
{
    while(!q.empty())q.pop();
    memset(dist,0x7f,sizeof(dist));
    int i,j,v,temp;
    dist[0][S]=0;
    in[0][S]=1;
    q.push(Lux(0,S));
    while(!q.empty())
    {
        Lux U=q.front();q.pop();in[U.x][U.y]=0;
        for(j=0;j+U.x<=lig;j++)
        {
            for(i=HEAD[j][U.y];i;i=E[j][i].next)
            {
                v=E[j][i].v;
                if(dist[j+U.x][v]>dist[U.x][U.y]+E[j][i].len+cost)
                {
                    dist[j+U.x][v]=dist[U.x][U.y]+E[j][i].len+cost;
                    if(!in[j+U.x][v])in[j+U.x][v]=1,q.push(Lux(j+U.x,v));
                }
            }
        }
    }
    double ret=99999999999.999;
    for(i=0;i<=lig;i++)ret=min(ret,dist[i][T]);
    return ret;
}
 
void work()
{
    int i,j,k;
    double a,b,c;
    int ia,ib;
    int s,t,v;
    /*i just think it's not 
        [graceful]
    to input in the main function. */
    scanf("%d%d%d%d%d",&n,&m,&lig,&gas,&cost);
    for(i=1;i<=n;i++)
    {
        trie.insert();
        if(k=trie.judge())
        {
            sta[i]=++num;
            gas_station[num]=i;
            if(k==1)s=i;
            if(k==3)t=i;
        }
        scanf("%lf%lf",&a,&b);
        if(k==1||k==3)continue;
        if(a>eps)
            red[i]=1,ave[i]=a*a/2.0/(a+b);          
    }
    for(i=1;i<=m;i++)
    {
        ia=trie.insert();
        ib=trie.insert();
        scanf("%s",ttt);
        scanf("%lf",&c);
        add(ia,ib,c);
        add(ib,ia,c);
    }
 
    for(i=1;i<=num;i++)
    {
        prespfa(gas_station[i]);
        for(j=1;j<=num;j++)
        {
            v=gas_station[j];
            if(j!=i)
            {
                for(k=0;k<=lig;k++)
                {
                    if(dist[k][v]<inf)
                    {
                        ADD(k,i,j,dist[k][v]);
                    }
                }
            }
        }
    }
    printf("%.3lf\n",divspfa(sta[s],sta[t])-cost);
}
 
int main()
{
//  freopen("pathplan.in","r",stdin);
//  freopen("pathplan.out","w",stdout);
//  freopen("test.in","r",stdin);
    work();
    return 0;
}



你可能感兴趣的:(路径规划,BZOJ3627,JLOI2014,分层图,二维缩项)