首页 > 其他分享 >分层图最短路

分层图最短路

时间:2022-08-28 10:13:19浏览次数:86  
标签:int 短路 tot 线路 分层 maxn include define

目前做了两道题

通信线路

回家的路

现在对分层图的理解是建立好几个图,然后每层图,每个点之间建边

通信线路

在郊区有 NN 座通信基站,PP 条 双向 电缆,第 ii 条电缆连接基站 AiAi 和 BiBi。

特别地,11 号基站是通信公司的总站,NN 号基站位于一座农场中。

现在,农场主希望对通信线路进行升级,其中升级第 ii 条电缆需要花费 LiLi。

电话公司正在举行优惠活动。

农产主可以指定一条从 11 号基站到 NN 号基站的路径,并指定路径上不超过 KK 条电缆,由电话公司免费提供升级服务。

农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。

求至少用多少钱可以完成升级。

输入格式

第 1 行:三个整数 N,P,K。

第 2..P+1 行:第 i+1 行包含三个整数 Ai,Bi,Li。

输出格式

包含一个整数表示最少花费。

若 11 号基站与 N 号基站之间不存在路径,则输出 −1−1。

数据范围

0≤K<N≤1000,
1≤P≤10000,
1≤Li≤1000000

输入样例:

5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6

输出样例:

4

前k个线路可以免费,也就是说,需要建立一个k层的图

这个的分层似乎和其他的不太一样,目前还是有些疑惑,理解后再补

具体看代码和注释吧,来自蓝书

通信线路
 #include<iostream>
#include<cstring>
#include<queue>
#define int long long
#define mkp make_pair
#define sec second 
#define fir first 
using namespace std;
const int maxn=2e5+10;
//题目是分层图
//我们把免费操作转化成零边,如果进行免费操作,就进入下一层
//就是说,可以建好几层图,第0层就是一条边也不去掉,第1曾去掉最大的那条边,第2曾去掉前2大的边.....
int n,p,k;
int head[maxn],nex[maxn],ver[maxn],edge[maxn],tot;
int d[1001][1001];//或者是d[i][j]是到i点,去掉j条边后的最大值中的最小值(看到这里应该想到似乎可以二分)
bool ju[1001][1001];
priority_queue<pair<int, pair<int,int>>>q;
inline void add(int x,int y,int z)
{
    ver[++tot]=y;
    edge[tot]=z;
    nex[tot]=head[x];
    head[x]=tot;
}
void dijkstra()
{
    memset(d,0x7f7f,sizeof(d));
    d[1][0]=0;
    q.push(make_pair(0,mkp(1,0)));
    while(q.size())
    {
        int x=q.top().sec.fir,l=q.top().sec.sec;
        q.pop();
        if(ju[x][l])continue;//从1到x
        ju[x][l]=1;
        for(int i=head[x];i;i=nex[i])
        {
            int y=ver[i],z=edge[i];//x可以直接连到y
            if(d[y][l]>max(d[x][l],z))//同一层 从x->y还有个边x,如果到y时去掉l条边后的值不如先去掉l条边到x再到y小
            //(就是说走x这条路可以获得更小的值),
            //为什么max(d[x],z)呢,因为此路线中的最大的中的第l+1个是d[x]或者d[x]<z的话
            //就要把z插在d[x]值前面,就是说此路线中的最大的中的第l+1个变成了z
            {
                d[y][l]=max(d[x][l],z);
                q.push(mkp(-d[y][l],mkp(y,l)));
            }
            if(l<k&&d[y][l+1]>d[x][l])//这里是说把x,y之间的边free掉,那么进入下一层图,至于为什么是大于,还是因为x线路存在更优解
            {
                d[y][l+1]=d[x][l];
                q.push(mkp(-d[y][l+1],mkp(y,l+1)));
            }
        }
    }
}
signed main()
{
    cin>>n>>p>>k;
    for(int i=1;i<=p;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        add(x,y,z);
        add(y,x,z);
    }
    dijkstra();
    int ans=0x7f7f7f7f;
    for(int i=0;i<=k;i++)//防止没有走k层就到n了
    ans=min(ans,d[n][i]);
    if(ans==0x7f7f7f7f)cout<<-1;
    else cout<<ans<<endl;
    return 0;
}

回家的路

题目描述

2046 年 OI 城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由2n2n条地铁线路构成,组成了一个nn纵nn横的交通网。如下图所示,这2n2n条线路每条线路都包含nn个车站,而每个车站都在一组纵横线路的交汇处。

出于建设成本的考虑,并非每个车站都能够进行站内换乘,能够进行站内换乘的地铁站共有mm个,在下图中,标上方块标记的车站为换乘车站。已知地铁运行 1 站需要 2 分钟,而站内换乘需要步行 1 分钟。Serenade 想要知道,在不中途出站的前提下,他从学校回家最快需要多少时间(等车时间忽略不计)。

输入格式

第一行有两个整数n,mn,m。

接下去mm行每行两个整数x,yx,y,表示第xx条横向线路与第yy条纵向线路的交

汇站是站内换乘站。

接下去一行是四个整数x_1,y_1,x_2,y_2x1​,y1​,x2​,y2​。表示 Serenade 从学校回家时,在第 x_1x1​条横向线路与第y_1y1​条纵向线路的交汇站上车,在第x_2x2​条横向线路与第y_2y2​条纵向线路的交汇站下车。

输出格式

输出文件只有一行,即 Serenade 在合理选择线路的情况下,回家所需要的时间。如果 Serenade 无法在不出站换乘的情况下回家,请输出-1。

输入输出样例

输入 #1
2 1
1 2
1 1 2 2
输出 #1
5
输入 #2
6 9
2 1
2 5
3 2
4 4
5 2
5 6
6 1
6 3
6 4
1 1 4 6
输出 #2
27
输入 #3
6 10
2 1
2 5
3 2
4 4
5 2
5 6
6 1
6 3
6 4
6 6
1 1 4 6
输出 #3
26

说明/提示

对于 30%的数据,n≤50,m≤1000;

对于 60%的数据,n≤500,m≤2000;

对于 100%的数据,n≤20000,m≤100000;

 

这个应该算一个典型的分层图吧,有m+2个点,那么我们按照横向和纵向建立两个图,那么总共2*m+4个点,i和i+m+2的边权为1,起点+m+2,终点+m+2的边权为0

分别按照横向和纵向排一次序,建图吧,记得是双向边

回家的路
 #include<iostream>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
#define int long long
#define pii pair<int,int>
#define mkp make_pair
#define fir first
#define sec second
using namespace std;
const int maxn=6e6+10;
int n,m,stx,sty,enx,eny;
int ver[maxn],val[maxn],head[maxn],nex[maxn],tot,d[maxn];
struct station
{
    int id;
    int x,y;
}a[maxn];
bool cmp1(station i,station j)
{
    if(i.x==j.x)return i.y<j.y;
    return i.x<j.x;
}
bool cmp2(station _,station __)
{
    if(_.y==__.y)return _.x<__.x;
    return _.y<__.y;
}
priority_queue<pii>q;
bool ju[maxn];
void dijkstra(int s)
{
    memset(d,0x7f7f7f,sizeof(d));
    d[s]=0;
    q.push(mkp(0,s));
    while(!q.empty())
    {
        int x=q.top().sec;
        q.pop();
        if(ju[x])continue;
        ju[x]=1;
        for(int i=head[x];i;i=nex[i])
        {
            int y=ver[i],z=val[i];
            if(d[y]>d[x]+z)
            {
                d[y]=d[x]+z;
                q.push(mkp(-d[y],y));
            }
        }
    }
    
}
inline void add(int x,int y,int z)
{
    ver[++tot]=y;
    val[tot]=z;
    nex[tot]=head[x];
    head[x]=tot;
}
inline void addd(int x,int y,int z)
{
    add(x,y,z);
    add(y,x,z);
}
signed main()
{
    cin>>n>>m;
    if(m==0)//特判一下
    {
        cout<<-1;
        return 0;
    }
    for(int i=1;i<=m+2;i++)
    {
        cin>>a[i].x>>a[i].y;
        a[i].id=i;
    }
    sort(a+1,a+m+3,cmp1);
    for(int i=1;i<=m+1;i++)
    {
        if(a[i].x==a[i+1].x)
        {
            addd(a[i].id,a[i+1].id,(a[i+1].y-a[i].y)*2);
        }
    }
    sort(a+1,a+m+3,cmp2);
    for(int i=1;i<=m+1;i++)
    {
        if(a[i].y==a[i+1].y)
        {
            addd(a[i].id+m+2,a[i+1].id+m+2,(a[i+1].x-a[i].x)*2);
        }
    }
    for(int i=1;i<=m;i++)addd(i,i+m+2,1);//两层图建边
    addd(m+1,m+1+m+2,0);
    addd(m+2,m+2+m+2,0);
    dijkstra(m+1);
    if(d[m+2]==0x7f7f7f)cout<<-1;
    else cout<<d[m+2];
    return 0;
}

这位大佬的bolg还有几个题目,有空再做吧

孤岛营救

Revamping Trails G

飞行路线

标签:int,短路,tot,线路,分层,maxn,include,define
From: https://www.cnblogs.com/qbning/p/16632279.html

相关文章