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\)

posted @ 2023-08-09 20:47  lnbyn  阅读(18)  评论(0编辑  收藏  举报