street 题解
题意简述:
-
\(n\)个街区,街区之间共有\(m\)条双向通行的道路,且任意两个街区可以通过这些道路互相到达。
-
我们要从\(1\)号街区走到\(n\)号街区,只会在总长度最短的若干条路径中选择一条走。
-
有\(k\)个街区由于开了很多咖啡店,我们只会从不经过任何一个这样的街区的最短路径中选择一条走。如果所有最短路径都会经过这样的街区,我们就会放弃出行。
-
求出行路程一路上经过的边权最小值中的最大值。(就是从\(1\)走到\(n\)的最短路的多种方案中,选择一种既能不经过那\(k\)个有咖啡店的点,同时这一路上最短的边权在多种方案中最长)同时如果所有最短路中都会经过咖啡的话,则不出行,答案即为\(0\)。
思路:
-
首先,题目说最短路,那么考虑能不能将判断咖啡与求最短边权加入到最短路中。
-
最短路跑\(dijkstra\)即可 -
那么显然求这个最短路过程中,最短边权是比较好更新的,判断路径有没有咖啡能不能走也不难,但是放在一起要考虑一些东西:
-
首先除最短路外,要记录到达该点经过的边权最小值中的最大值,与到达该点的最短路中是否全都是经过咖啡点的(以下改称路径是否合法吧)
-
首先题意明显最短路优先级更高!
-
那么在最短路更新时检测到了可以进行松弛操作时,第\(i\)点可以被第\(j\)点松弛时,直接将到点\(i\)的最短路径更新为\(min\)(到点\(j\)的最短路径,\(i\),\(j\)这条边边长)即可,同时将该点\(i\)判断最短路是否全部经过咖啡的值赋成点\(j\)该值,再特殊判断一下点\(i\)是否是咖啡点即可
-
另一种情况比较复杂:当最短路更新时检测到了目前两条路长度相等时:
-
首先判断该点是不是咖啡点,如果是的话怎么更新都没用
-
再判断这个点\(i\)原先到达的路径与\(j\)的最短路路径是否合法:
-
如果……算了太晚了明天再写
-
如果原来到达路径合法,修改了之后不合法,那么肯定不改
-
如果原来路径不合法,修改了之后也不合法,那么修不修改也没什么区别
-
如果原来路径合法,修改了之后也合法,那么就从两条路径中的最短路径选取较长的
-
如果原来路径不合法,修改了之后合法,那么一定要改,最短路径更新为修改来的最短路径(注意此时不能与原来路径的最短取最大值!!原来的路径已经不能走了!)
-
-
-
跑完一边最短路即可求出结果了
-
-
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define int long long
#define maxn 1000005
using namespace std;
void read(int &n){
n=0;int f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
n=(n<<3)+(n<<1)+ch-'0';
ch=getchar();
}
n*=f;
}
int n,m,k;
struct EDGE{
int to,val;
friend bool operator < (EDGE aaa, EDGE bbb){
return aaa.val > bbb.val;
}
};
vector <EDGE> g[maxn];
bool cof[maxn];
int dis[maxn];
bool vis[maxn];
bool flag[maxn];//ji lu shifou zouguo coffee
int minl[maxn];
priority_queue <EDGE> pq;
void dijkstra(){
memset(dis,0x3f,sizeof(dis));
memset(minl,0x3f,sizeof(minl));
dis[1]=0;
pq.push((EDGE){1,dis[1]});
int now,t,v;
while(!pq.empty()){
now=pq.top().to;pq.pop();
if(vis[now]==true){
continue;
}
vis[now]=true;
for(int j=0;j<g[now].size();j++){
t=g[now][j].to;
v=g[now][j].val;
if(dis[now]+v<dis[t]){
dis[t]=dis[now]+v;
flag[t]=flag[now];
if(cof[t]==true){
flag[t]=true;
}
minl[t]=min(minl[now],v);
if(vis[t]==false){
pq.push((EDGE){t,dis[t]});
}
}else if(dis[now]+v==dis[t]){
if(cof[t]==true){
flag[t]=true;
minl[t]=max(minl[t],min(minl[now],v));
}else{
if(flag[t]==true){
if(flag[now]==false){
flag[t]=false;
minl[t]=min(minl[now],v);
}else{
minl[t]=max(minl[t],min(minl[now],v));
}
}else{
if(flag[now]==false){
minl[t]=max(minl[t],min(minl[now],v));
}
}
}
}
}
}
}
signed main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
read(n),read(m),read(k);
int u,v,w;
for(int i=1;i<=k;i++){
read(u);
cof[u]=true;
}
for(int i=1;i<=m;i++){
read(u),read(v),read(w);
g[u].push_back((EDGE){v,w});
g[v].push_back((EDGE){u,w});
}
dijkstra();
if(flag[n]==true){
printf("0");
}else{
printf("%lld",minl[n]);
}
return 0;
}
完结撒花
原发布于 \(2023.2.9\)