2020牛客暑期多校训练营第五场Portal

Portal

原题请看这里

题目描述:

您现在在一家大工厂里。可以将工厂识别为具有 N N 个顶点和 M M 个边的图形。每个边缘都有其长度。您有 k k 个任务要做。第 i i 个任务将顶点 a i a_i ,选择一个块,然后将其发送到顶点 b i b_i 。您应该按照从 1 1 号到k号的顺序完成任务。最初,您站在 v e c t e x 1 vectex 1
你手里拿着枪。当您处于某个顶点 u u 时,您可以向地面上射击,然后将在顶点 u u 建立一个门户。当工厂中有两个门户时,假设它们分别位于 u u v v 处,则可以在 u u v v 之间进行免费转换(就像连接长度为 0 0 u u v v 的边一样)。
您的手边还有一个遥控器。它使您可以随时随地关闭门户网站(一次关闭一个门户网站,而不是一次关闭所有门户网站)。而且,最多可以有两个现有门户。因此,如果要在存在两个门户网站时创建另一个门户网站,则必须先使用控制器将其关闭,然后再创建。
您需要找到必须步行的最小距离才能完成所有 k k 个任务。

输入描述:

第一行包含以空格分隔的三个正整数 N N M M k k
接下来的m行中,每个包含三个整数 u i u_i v i v_i w i w_i ,表示连接顶点 u i u_i v i v_i 的双向边,长度为 w i w_i 。接下来的 k k 行中,每个行包含两个整数 a i a_i b i b_i ,指示第 i i 个任务的开始和结束。
1 1 \leq N N \leq 300 300
1 1 \leq M M \leq 40000 40000
1 1 \leq k k \leq 300 300
1 1 \leq u i u_i v i v_i \leq n n
0 0 \leq w i w_i \leq 1 0 9 10 ^ 9
1 1 \leq a j a_j b j b_j \leq n n
该图保证已连接。

输出描述:

输出一个整数,表示最小距离。

样例:

样例输入1:

5 4 2
1 2 1
2 3 1
3 4 1
4 5 1
1 5
2 4

样例输出1:

5

说明:

Solution for sample 1: walk from 1 to 5, create portals at 2 and 4 when passing by. 
And then walk from 5 to 4, then you could use portals to complete the second mission.

样例输入2:

6 10 3
1 1 6
5 6 9
3 5 8
1 4 1
2 4 7
6 6 10
1 4 2
6 5 10
3 5 2
3 1 9
1 5
2 5
4 3

样例输出2:

28

样例输入3:

6 10 3
1 1 3
3 1 1
6 2 3
1 6 10
4 1 1
3 1 2
5 6 9
5 4 10
6 3 4
3 4 4
3 5
3 6
6 5

样例输出3:

16

思路:

题目大意:从点 1 1 出发,你要按顺序完成 k k 个任务,每个任务有要求的起点和终点。途中你可以在所在的位置建立一个传送门,而同时只能用两个传送门存在,如果超过两个,则必须(远程)关闭任意一个传送门。
首先明确这道题用最短路动态规划来做, k k 个任务都有起点终点,也就是说要走过 2 2 k个点。 d p dp 数组需要记录 4 4 个状态:当前已经完成了 i i 个任务,当前在 k k 节点,传送门位置分别在 x x y y ,也就是 d p [ i ] [ k ] [ x ] [ y ] dp[i][k][x][y] ------标准的暴力写法!
但是在途中你可以在你所在位置建立一个传送门,所以只需要记录远一点的那一个就行了,所以dp数组的维度就变成了三维: d p [ i ] [ k ] [ y ] dp[i][k][y]
而题目说了输入的节点是按 1 1 ~ N N 顺序的,所以不用记录当前节点的位置,于是dp数组的维度就变成了二维: d p [ i ] [ y ] dp[i][y]
根据以上信息,我们可以写出状态转移的方程式:
1. 1. a i a_i 直接走到 a i + 1 a_{i+1}
2. 2. 枚举 a i + 1 a_{i+1} 后放传送门的位置:从 a i a_i 走到放传送门的位置,然后传送到另一个传送门,走到 a i + 1 a_{i+1}
3. 3. 直接传送到另一个传送门,在从另一个传送门走到放传送门的位置,再走到 a i + 1 a_{i+1}
(有点复杂)
所以我们只要在没有传送门的情况下先对所有点跑Floyd,再用动态规划求出最小距离

AC Code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[1005]={1},fl[1005][1005],dp[1005][1005],w,n,m,k,u,v,ans=1e18;
int main()
{
	memset(fl,0x3f,sizeof(fl));
	memset(dp,0x3f,sizeof(dp));
	dp[0][1]=0;
	scanf("%lld%lld%lld",&n,&m,&k);
	k*=2;
	for(int i=0;i<=n;i++)
		fl[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&u,&v,&w);
		fl[u][v]=fl[v][u]=min(w,fl[u][v]);
	}
	for(int i=1;i<=k;i++)
		scanf("%lld",a+i);
	for(int l=1;l<=n;l++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				fl[i][j]=min(fl[i][l]+fl[l][j],fl[i][j]);//Floyd求最短路			
	for(int i=1;i<=k;i++)
		for(int j=1;j<=n;j++)
		{
			dp[i][j]=min(dp[i][j],dp[i-1][j]+fl[a[i-1]][a[i]]);
			for(int l=1;l<=n;l++)
				dp[i][l]=min(dp[i][l],dp[i-1][j]+min(fl[a[i-1]][l]+fl[j][a[i]],fl[j][l]+fl[l][a[i]]));
		}
	for(int i=1;i<=n;i++)
		ans=min(ans,dp[k][i]);
	printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/s260127ljy/article/details/107592732
今日推荐