首页 > 其他分享 >P7192 [COCI2007-2008#6] GEORGE 题解

P7192 [COCI2007-2008#6] GEORGE 题解

时间:2024-01-21 18:55:05浏览次数:34  
标签:ch P7192 题解 Luka read int 2008 rightarrow dis

题目简述

给定一张 $n$ 个点 $m$ 条边的无向图,从 $u_i \rightarrow v_i$ 需要用时 $w_i$ 分钟。有一位 T 先生从 $0$ 时刻按有 $g$ 个点的序列顺序移动,即 $v_1 \rightarrow v_2 \rightarrow \cdots \rightarrow v_g$。还有一位卡车司机 Luka 从 $k$ 时刻开始从 $a$ 点出发,Luka 不能与 T 先生在同一时间走同一条路,问 Luka 从 $a$ 点到 $b$ 点的最短路。

题目分析

注意到 T 先生的移动顺序是一定的,所以我们可以先处理出每一个时刻 T 先生在哪一条边上。

接下来,我们考虑使用 Dijkstra 算法求最短路,设当前队首可以扩展的点为 $u$,从点 $a$ 到点 $u$ 所需的最短时间为 $dis_u$,与 $u$ 的连边为 $u \rightarrow v$,如果 T 先生在 $dis_u$ 时刻恰好走在 $u \rightarrow v$ 这条边上,我们可以让 Luka 等到 T 先生走开再走这条边,就是将边权增大在进行松弛。如果 T 先生没走的话直接松弛就好了。

最后答案是 $dis_b-k$,因为 Luka 是从 $k$ 时刻开始走的。

代码

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=1e3+10;
const int M=1e4+10;
int n,m,a,b,k,g,t[N],cnt,head[N],cnt2,vis1[N],E[N][N],dis[N],vis2[N][N]; 
pair<int,int> vis[M*1000];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
struct edge
{
	int to,next,value;
}e[M*2];
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
	    if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
	    x=(x<<1)+(x<<3)+ch-48;
	    ch=getchar();
	}
	return x*f;
}
inline void write(int x)
{
    if(x<0)
	{
    	putchar('-');
		x=-x;
	}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
void addedge(int u,int v,int w)
{
	e[++cnt]={v,head[u],w};
	head[u]=cnt;
}
int main()
{
	n=read();
	m=read();
	a=read();
	b=read();
	k=read();
	g=read();
	for(int i=1;i<=g;i++)
	{
		t[i]=read();
	}
	for(int i=1;i<=m;i++)
	{
		int u=read();
		int v=read();
		int w=read();
		addedge(u,v,w);
		addedge(v,u,w);
		E[u][v]=E[v][u]=w;
	}
	for(int i=1;i<=g-1;i++)
	{
		for(int j=1;j<=E[t[i]][t[i+1]];j++)
		{
			vis[++cnt2]={t[i],t[i+1]};
		}
		vis2[t[i]][t[i+1]]=cnt2;
	}
	memset(dis,0x3f,sizeof dis);
	q.push({k,a});
	dis[a]=k;
	while(!q.empty())
	{
		int u=q.top().second;
		q.pop();
		if(vis1[u]) continue;
		vis1[u]=1;
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to,w=e[i].value; 
			if((vis[dis[u]].first==u&&vis[dis[u]].second==v)||(vis[dis[u]].first==v&&vis[dis[u]].second==u))
			{
				w+=vis2[vis[dis[u]].first][vis[dis[u]].second]-dis[u];
			}
			if(dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				q.push({dis[v],v});
			}
		}
	}
	write(dis[b]-k);
	return 0;
}

标签:ch,P7192,题解,Luka,read,int,2008,rightarrow,dis
From: https://www.cnblogs.com/zhuluoan/p/17978167

相关文章

  • 洛谷 P9843 [ICPC2021 Nanjing R] Paimon Sorting 题解
    Descirption给出一个排序算法(用伪代码表示):SORT(A)forifrom1tonforjfrom1tonifa[i]<a[j]Swapa[i]anda[j]算出对于一个序列\(A=a_1,a_2,\cdots,a_n\)的所有前缀\(A_k=a_1,a_2,\cdots,a_k\)(\(1\lek\len\)),\(\operatorname{SORT}(A_......
  • AT_abc337_d 的题解
    AT_abc337_d的题解题目大意给你一个\(H\timesW(H\timesW\leq2\times10^5)\)的矩阵,矩阵由o、x和.构成。存在一种操作:将一个.变成o。问在一段连续的区间内,需要进行多少次操作才可以将同一行或同一列中的连续\(k\)个数都变为o,若无法完成,输出-1。思考过程看......
  • AT_abc337_c的题解
    AT_abc337_c的题解题目大意就是给你一个数组$a=(a_1,a_2,\ldots,a_n)$,若$a_i$为$-1$,那么这个数的下标就是输出序列的开头,否侧,这个数在输出序列中排在$a_i$的下一个。思考过程从样例中不难发现:$1,2,\ldots,n$中的每一个数最多在$a$中出现一次;输出序列中的每一个......
  • P10073 [GDKOI2024 普及组] 刷野 II 的题解
    P10073[GDKOI2024普及组]刷野II的题解谨以此篇题解记录我考场上唯一通过的一题~解题思路可以考虑定义两个指针x和y,分别为左侧攻击到哪里和右侧。此时,从两侧线性想中间递推,若先打左边的代价小就打左边的,否则就打右边的。按照这个方法向中间推就可以了。Code#include<......
  • ABC337 E Bad Juice 题解
    QuestionABC337EBadJuice交互题\(n\)瓶果汁中有\(1\)瓶是坏的,现在需要把这些果汁分给\(m\)个人,每个人可以喝任意瓶,然后通过\(m\)个人的回复判断哪一瓶是坏的需要输出最小的\(m\)以及坏果汁的编号Solution\(m\)返回的结果由\(01\)构成,自然而然想到二进制,考虑......
  • ABC337 D Cheating Gomoku Narabe 题解
    QuestionABC337DCheatingGomokuNarabe给出一个\(H\timesW\)的矩阵,由o,x,.组成,一次操作为把一个.变成o,问需要最少多少次操作使得横着或竖着有连续的\(K\)个oSolution先来考虑只有一行的情况,我们定义一个长度为\(K\)的"窗口",假设需要把这个"窗口"里面的所有......
  • CF526F Pudding Monsters 题解
    题目链接:CF或者洛谷析合树真是连续段问题的降智神器先看下题目的一些特殊性,每行每列恰好有一个棋子。考虑特殊性,\(n\timesn\)的棋盘,那么就该判断是否有\(n\)个棋子,容易观察到,也就是相当于每一行并且每一列都有一个棋子。而容易知道,这些棋子所在的行或者列拿出来应当是“......
  • P4148 简单题 题解
    QuestionP4148简单题有一个\(n\timesn\)的棋盘,每个格子内有一个整数,初始时全部为\(0\),现在需要维护两种操作1xy将格子\(x,y\)里的数字加上\(A\)2x1y1x2y2输出\(x_1,y_1,x_2,y_2\)这个矩形内的数字和强制在线Solution因为强制在线,没法用CDQ什么乱搞,这......
  • P4747 [CERC2017] Intrinsic Interval 题解
    题目链接:IntrinsicInterval讲讲析合树如何解决这种问题,其实这题很接近析合树的板题的应用。增量法进行析合树建树时,需要用ST表预处理出\(max\)和\(min\)以便\(O(1)\)查询极差,然后线段树去维护\([l,r]\)上的极差减区间端点做差即\(diff-(r-l)\),当这玩意等于\(0\)时......
  • P8112 [Cnoi2021] 符文破译 题解
    题目传送门思路先看数据范围,我们发现两个字符串的长度最大会达到\(5\times10^7\)。这立刻打消了我用暴力的想法。于是,我选择了用KMP模式匹配,这一个能够在线性时间内判定字符串\(A\)是否是字符串\(B\)的字串,并求出字符串\(A\)在字符串\(B\)中各次出现的位置。如......