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

Portal

原题请看这里

题目描述:

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

输入描述:

第一行包含以空格分隔的三个正整数 N N N M M M k k k
接下来的m行中,每个包含三个整数 u i u_i ui v i v_i vi w i w_i wi,表示连接顶点 u i u_i ui v i v_i vi的双向边,长度为 w i w_i wi。接下来的 k k k行中,每个行包含两个整数 a i a_i ai b i b_i bi,指示第 i i i个任务的开始和结束。
1 1 1 ≤ \leq N N N ≤ \leq 300 300 300
1 1 1 ≤ \leq M M M ≤ \leq 40000 40000 40000
1 1 1 ≤ \leq k k k ≤ \leq 300 300 300
1 1 1 ≤ \leq u i u_i ui v i v_i vi ≤ \leq n n n
0 0 0 ≤ \leq w i w_i wi ≤ \leq 1 0 9 10 ^ 9 109
1 1 1 ≤ \leq a j a_j aj b j b_j bj ≤ \leq n 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 1出发,你要按顺序完成 k k k个任务,每个任务有要求的起点和终点。途中你可以在所在的位置建立一个传送门,而同时只能用两个传送门存在,如果超过两个,则必须(远程)关闭任意一个传送门。
首先明确这道题用最短路动态规划来做, k k k个任务都有起点终点,也就是说要走过 2 2 2k个点。 d p dp dp数组需要记录 4 4 4个状态:当前已经完成了 i i i个任务,当前在 k k k节点,传送门位置分别在 x x x y y y,也就是 d p [ i ] [ k ] [ x ] [ y ] dp[i][k][x][y] dp[i][k][x][y]------标准的暴力写法!
但是在途中你可以在你所在位置建立一个传送门,所以只需要记录远一点的那一个就行了,所以dp数组的维度就变成了三维: d p [ i ] [ k ] [ y ] dp[i][k][y] dp[i][k][y]
而题目说了输入的节点是按 1 1 1~ N N N顺序的,所以不用记录当前节点的位置,于是dp数组的维度就变成了二维: d p [ i ] [ y ] dp[i][y] dp[i][y]
根据以上信息,我们可以写出状态转移的方程式:
1. 1. 1. a i a_i ai直接走到 a i + 1 a_{i+1} ai+1
2. 2. 2.枚举 a i + 1 a_{i+1} ai+1后放传送门的位置:从 a i a_i ai走到放传送门的位置,然后传送到另一个传送门,走到 a i + 1 a_{i+1} ai+1
3. 3. 3.直接传送到另一个传送门,在从另一个传送门走到放传送门的位置,再走到 a i + 1 a_{i+1} ai+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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值