P4568 [JLOI2011]飞行路线(分层图)

机房dalao推荐写的。。。(标签分层图)

经过前几题的分层图的洗礼,我深刻地体会到了分层图的优点和好处(主要是不想打dp....)

先说题吧....

很明确,模型是最短路,但是,怎么跑k个,是个问题....

解题过程:

1、先跑最短路,记录路径,然后找路径上的k条最长边,删掉

tips:贪心,很容易hack掉。

2、建两层的分层图(以前打的都是两层居多)

tips:会跑出0来....

solution:

 主要就是:怎么连边喽....一开始老是卡住

连边有2种情况:

  1. 同一层之间的边,边权为题目给的边权,同层之间连
  2. 层与层之间,一个点连到下一层的它对应的出点,边权为0,为单向边

一共K层,上层可以跑到下层的出点,却不能回去,这就是一次免票。

然后跑最短路,最后查t+n*k那个点的dis就可以了。

for(int i=1;i<=m;i++)
    {
        int x,y,z;
        x=read();y=read();z=read();
        addedge(x,y,z);
        addedge(y,x,z);
        for(int j=1;j<=k;j++)
        {
            addedge(x+n*j,y+n*j,z);
            addedge(y+n*j,x+n*j,z);
            addedge(x+(j-1)*n,y+j*n,0);
            addedge(y+(j-1)*n,x+j*n,0);
        }
    }

如上,分层连边。

之后就是一个spfa的事了(然而我各种常数(畜生)优化+O2卡到比旁边dalao快600ms的地步哈哈哈哈)

值得注意:

1、最后要把每一层的t点连在一起,因为如果在第二层就跑到了最短,在最后一层的t并不能查到正确答案

2、一共有k+1层,所以初始化dis要k+1层,因为这个卡了一小会...

#include<bits/stdc++.h>
using namespace std;
const int maxn=6e6+10;
int n,m,k;
int s,t;
inline int read()
{
    int x=0,f=1;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
struct edge
{
    int to,next,dis;
}e[maxn];
int head[maxn],cnt;
inline void addedge(int from,int to,int dis)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    e[cnt].dis=dis;
    head[from]=cnt;
}
int dis[maxn],vis[maxn];
struct cmp
{
    bool operator () (int a,int b)
    {
        return dis[a]>dis[b];
    }
};
priority_queue < int , vector < int > , cmp > q;
//queue < int > q;
void spfa(int s)
{

    for(int i=0;i<=(k+1)*n;i++)
    {
        dis[i]=2147483647;
        vis[i]=0;
    }
    //memset(dis,0x3f,sizeof(dis));
    q.push(s);
    dis[s]=0;
    vis[s]=1;
    while(!q.empty())
    {
        //cout<<233;
        int u=q.top();
        //int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].dis)
            {
                dis[v]=dis[u]+e[i].dis;
                if(vis[v]==0)
                {
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
}
int main()
{
    n=read();
    m=read();
    k=read();
    s=read();
    t=read();
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        x=read();
        y=read();
        z=read();
        addedge(x,y,z);
        addedge(y,x,z);
        for(int j=1;j<=k;j++)
        {
            addedge(x+n*j,y+n*j,z);
            addedge(y+n*j,x+n*j,z);
            addedge(x+(j-1)*n,y+j*n,0);
            addedge(y+(j-1)*n,x+j*n,0);
        }
    }
    for(int i=1;i<=k;i++)
    addedge(t+(i-1)*n,t+i*n,0);
    spfa(s);
    cout<<dis[t+k*n];//printf("%d",dis[t+k*n]);
    return 0;
}

现在来说一说dp和分层图的关系:

首先,分层图的“层”是什么,它就是dp中的状态。在一些图论题目中,状态不好转移,就可以使用分层图进行转移,不需要再管“从哪转移”这个问题,剩下的最优解直接交给spfa就行了。(最优贸易

这些状态之间可以互相转移,一般在二维或是以上,可以省去一些不相关状态的枚举,但是因为spfa的广泛枚举性还是会枚举更多“不是最优解”的状态的。

(完)

 

猜你喜欢

转载自www.cnblogs.com/ajmddzp/p/11503135.html
今日推荐