1496 架设电话线
这里涉及到一个知识点叫做 分层求最短路径
好像是个很牛的东西
一句话:在加权无向图上求出一条从 1 号结点到 N 号结点的路径,使路径上第 K+1 大的边权尽量小
嗯。。。
我日常的没有任何思路,难不成是一个贪心?
使用分层计算,用二维组表示坐标,然后进行每一层求最短路径,分层的时候一定要从低到高开始
分层求最短路类似于递归分层
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<queue>
using namespace std;
const int N = 1e3+10,M = 2e5+10,INF = 0x3f3f3f3f;//记录长度
typedef pair<int,int> P;
int n,m,k,cnt;
int head[M],ver[M],nex[M],edge[M],vis[M],dis[M];
void add(int x,int y,int w)//邻接表存图
{
ver[++cnt] = y;
edge[cnt] = w;
nex[cnt] = head[x];
head[x] = cnt;
}
void read()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1,x,y,w;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);add(y,x,w);
for(int j=1;j<=k;j++)
{
add(j*n+x,j*n+y,w);add(j*n+y,j*n+x,w);//枚举位置进行加边
add((j-1)*n+x,j*n+y,0);//加边
add((j-1)*n+y,j*n+x,0);//加边
}
}
}
void dj()
{
priority_queue<P> q;
for(int i=0;i<=M;i++) dis[i] = INF;
q.push(make_pair(0,1)); dis[1] = 0;//初始化dis数组
while(q.size())
{
int u = q.top().second;q.pop();//取出队首进行操作
if(vis[u]) continue;
vis[u] = 1;//未标记标记
for(int i=head[u];i;i = nex[i])
{
int v = ver[i],w = edge[i];
if(dis[v] > max(dis[u],w))
{
dis[v] = max(dis[u],w);//更新dis数组
if(!vis[v]) q.push(make_pair(-dis[v],v));//进行标记,存反距离
}
}
}
}
void solve()
{
if(dis[k*n+n]!=INF) printf("%d\n",dis[k*n+n]);
else printf("-1\n");
}
int main()
{
read();
dj();
solve();
return 0;
}
接下来我们用一种新的方法来做这个题,也是我之前没有听说过的算法,二分最短路
好像很神奇的啊
其实很普通,就是不断地二分枚举点,看什么时候满足最短路径地性质
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10,INF = 0x3f3f3f3f;
int head[N],ver[N],nex[N],edge[N],vis[N],dis[N];
typedef pair<int,int> P;
int l=0,r=1e6,mid;
int n,m,k,cnt;
void add(int x,int y,int w)//邻接表
{
ver[++cnt] = y;
edge[cnt] = w;
nex[cnt] = head[x];
head[x] = cnt;
}
void read()//输入,并且存储
{
int x,y,w;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);add(y,x,w);
}
}
bool check(int x)
{
for(int i=0;i<N;i++)
dis[i] = INF,vis[i]=0;
priority_queue<P> q;
q.push(make_pair(0,1));dis[1] = 0;
while(q.size())
{
int u =q.top().second;q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i=head[u];i;i=nex[i])
{
int v = ver[i],w = edge[i];
int nd = dis[u] + (w>x?1:0);
if(dis[v] > nd){
dis[v] = nd;
if(!vis[v])
q.push(make_pair(-dis[v],v));
}
}
}
return (dis[n] <= k);//判断是否满足最短路
}
void solve()
{
while(l<=r)
{
mid = ((r+l)>>1);
if(check(mid))
r = mid-1;
else l = mid+1;//二分寻找最短路径
}
if(r==1e6) puts("-1");
else printf("%d\n",l);
}
int main()
{
read();
solve();
return 0;
}