首页 > 其他分享 >题解 P6880 [JOI 2020 Final] オリンピックバス

题解 P6880 [JOI 2020 Final] オリンピックバス

时间:2023-11-05 22:00:49浏览次数:34  
标签:le int 题解 短路 路径 lj 2020 Final dis

洛谷

题意

应该显然,注意最多只能翻转一条边,并且可以不翻转。

分析

首先观察数据范围 \(2\le N \le 200\),\(1\le M \le 5\times 10^4\),可以发现我们的 \(N\) 和 \(M\) 并不是同级的,因此,在众多的最短路算法中,我们应当选择不加堆优化的 dijkstra 算法,并且使用邻接矩阵,这是 \(O(n^2)\) 的时间复杂度,加入使用了堆优化或者使用邻接表,这就会使我们的最短路的时间变大。

接下来就是这道题比较巧妙的地方了,我们都知道 \(M\le 1000\) 的暴力怎么打,使用不加堆优化的迪杰,加上枚举翻转的边,时间复杂度是 \(O(M\times N^2)\)。但是这 \(m\) 次最短路并不是都是必须的,首先,假如我们枚举的这条边并不在 \(1\) 到 \(n\) 或 \(n\) 到 \(1\) 的最短路当中,那么翻转场此边并不会影响原来的路径的大小,但是我们的最短路可能会因此发生改变,不过只需要用原来 \(1\) 到 \(v\) 的最短路加上 \(u\) 到 \(n\) 的最短路加上翻转的边,与原最短路取小值即可。

那么在原最短路径的边呢,没有什么高大上的算法,直接和暴力一样即可。

接下来分析一下时间复杂度,我们的暴力是 \(O(n^2)\),不在最短路上的取答案是 \(O(1)\),而最短路径上的边数,最多只有 \(O(n)\)。

注意,这里的最短路径上的边,是指确定的一条路径,这条路径可以用记转移来的结点,也就是最短路径树解决,而不是可能出现在最短路径上的边。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e2+5;
const int M = 5e4+5;
const int INF = 0x3f3f3f3f3f3f;
inline int read() {
	int x;
	scanf("%lld",&x);
	return x;
}
int n, m;
struct Edge {
	int u,v,c,d;
} edge[M];

int lj[N][N],g[N][N],mark[N],dis[5][N],fa[5][N],vis[2][N][N];
//dis[0] 1 正  dis[1] n 正  dis[2] 1 反 dis[3] n 反 dis[4] ls

inline void dj(int st,int *dis,int *fa) {
	for(int i=1; i<=n; ++i) dis[0]=dis[i]=INF,mark[i]=fa[i]=0;
	dis[st]=0;
	while(1) {
		int now=0;
		for(int i=1; i<=n; ++i) if(!mark[i]&&dis[i]<dis[now]) now=i;
		if(!now) break;
		mark[now]=1;
		for(int i=1; i<=n; ++i) if(dis[i]>dis[now]+lj[now][i]) dis[i]=dis[now]+lj[now][i],fa[i]=now;
	}
	return ;
}

signed main() {
	n=read(),m=read();
	for(int i=1; i<=m; ++i) edge[i]=<%read(),read(),read(),read()%>;
	memset(lj,0x3f,sizeof lj),memset(g,0x3f,sizeof g);
	for(int i=1; i<=m; ++i) {
		int u=edge[i].u,v=edge[i].v,c=edge[i].c;
		g[u][v]=min(g[u][v],c);
		if(g[u][v]<lj[u][v]) swap(g[u][v],lj[u][v]);
	}
	dj(1,dis[0],fa[0]),dj(n,dis[1],fa[1]);
	for(int i=1; i<=n; ++i) for(int j=i; j<=n; ++j) swap(lj[i][j],lj[j][i]);
	dj(1,dis[2],fa[2]),dj(n,dis[3],fa[3]);
	for(int i=1; i<=n; ++i) for(int j=i; j<=n; ++j) swap(lj[i][j],lj[j][i]);
	int res=dis[0][n]+dis[1][1];
	if(dis[0][n]<INF) for(int now=n; now; now=fa[0][now]) vis[0][fa[0][now]][now]=1;
	if(dis[1][1]<INF) for(int now=1; now; now=fa[1][now]) vis[1][fa[1][now]][now]=1;
	for(int i=1; i<=m; ++i) {
		int u=edge[i].u,v=edge[i].v,c=edge[i].c,d=edge[i].d;
		int len1=lj[u][v],len2=lj[v][u];
		if(lj[u][v]==c) lj[u][v]=g[u][v];
		lj[v][u]=min(lj[v][u],c);
		int tot=d;
		if(vis[0][u][v]) dj(1,dis[4],fa[4]),tot+=dis[4][n];
		else tot+=min(dis[0][n],dis[0][v]+dis[3][u]+c);

		if(vis[1][u][v]) dj(n,dis[4],fa[4]),tot+=dis[4][1];
		else tot+=min(dis[1][1],dis[1][v]+dis[2][u]+c);
		
		res=min(res,tot);
		lj[u][v]=len1,lj[v][u]=len2;
	}
	cout<<(res>=INF?-1:res)<<"\n";
	return 0;
}

总结起来,这道题利用了最短路的边数小,以及不加堆优化的 dijkstra,这两个平时并不多用的性质,是一道最短路好题。

标签:le,int,题解,短路,路径,lj,2020,Final,dis
From: https://www.cnblogs.com/djh0314/p/17811292.html

相关文章

  • 【题解】NOIP2021 - 方差
    NOIP2021-方差https://www.luogu.com.cn/problem/P7962想当年我第一次站在noip赛场上,过了T1剩下三题就一题不会了……幸好这题拿了点分水了个一等。观察操作:若对于连续的三个数\(a,b,c\),对\(b\)进行一次操作后就变成了\(a,a+c-b,c\)。求出两个数组的差分数组:\(b-a,c......
  • 2023联合省选 题解
    目录D1T1P9166[省选联考2023]火车站D1T2P9167[省选联考2023]城市建造D1T3P9168[省选联考2023]人员调度D2T1P9169[省选联考2023]过河卒D2T2P9170[省选联考2023]填数游戏D2T3P9171[省选联考2023]染色数组D1T1P9166[省选联考2023]火车站性质很好找。关......
  • 题解 P6878 [JOI 2020 Final] JJOOII 2
    好久没写题解,水一篇。题意题意显然。分析看到这道题,我们就应该进行一个小贪心,对于最左边某一字符,直到最右边的这一字符,我们不会在中间删除同样的字符,不然则可以保留这一字符,将两边往内缩。也就是说,我们确定了最左边的J后,那么留下最后一个J必然是当前这个J的后面的第\(......
  • ARC_068F Solitaire题解
    非常骚的一道题首先看数据范围就很像dp(而且在dp专题里),尝试直接dp,发现不太行手玩一波样例,发现答案是2的若干次方乘一个系数。我们发现“若干”=n-k-1,这是巧合吗!?思索一番,会发现当我们取完k个数后剩下的n-k个数取法就为2^(n-k-1),为什么呢?可以把每次操作看成“前取“”or......
  • 2023年11月第一周题解-------数组
    1.问题A:LY学长的随机数解题思路第一种思路是先去重后排序第二种思路是先排序再去重解题方法暴力遍历#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>#include<time.h>#defineN10voidquickSort......
  • P9821 [ICPC2020 Shanghai R] Sum of Log
    原题链接题意,求:\[\sum_{i=0}^{X}\sum_{j=[i=0]}^{Y}[i\&j=0]\lfloor\log_2(i+j)+1\rfloor\]为简洁,记\(\lg(x)=\lfloor\log_2(x)\rfloor,n=\max(X,Y)\)由于\(i\&j=0\)则\(i+j=i\operatorname{|}j\)则\(\lg(i+j)=\lg(i\operatorname{|}j)=\lg(......
  • CF1838C题解
    显然\(1\)不是质数,除二外偶数不是质数。然后分类讨论对于\(m\)为偶数,构造\[\begin{bmatrix}1&2&3&\cdots&m\\m+1&m+2&m+3&\cdots&2m\\&&\cdot\\&&\cdot\\&&\cdot\\......
  • CF859G 题解
    总结题意显然可以转化为序列问题嘛。给出序列\(A\{a_i\}\),你需要通过若干次操作使其归零。操作:选定\(d|n\)、\(k\)、\(r\),对于序列中所有满足\(i\bmodd=r\)的位置加上\(k\)。题解很明显,加减相互抵消,对于所有\(d\)、\(r\)相同的位置可以视作一次操作。如何表示......
  • CF773A 题解
    真的是蓝题?这真的不是小学数学题?我们是要求满足(其中\(a\)为正确数,\(b\)为总数)\[\frac{x+a}{y+b}=\frac{p}{q}\]的最小\(b\)。我们可以先把右式的分子分母变化到与\(\frac{x}{y}\)类似的大小。intbs1=x/p+(x%p!=0);intbs2=y/q+(y%q!=0);i......
  • 【洛谷 P1909】[NOIP2016 普及组] 买铅笔 题解(打擂台法)
    [NOIP2016普及组]买铅笔题目背景NOIP2016普及组T1题目描述P老师需要去商店买支铅笔作为小朋友们参加NOIP的礼物。她发现商店一共有种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。为了公平起见,P老师决定只买同一种包装的铅笔。商店不允许将铅笔的包装......