Portal
题目描述:
您现在在一家大工厂里。可以将工厂识别为具有
个顶点和
个边的图形。每个边缘都有其长度。您有
个任务要做。第
个任务将顶点
,选择一个块,然后将其发送到顶点
。您应该按照从
号到k号的顺序完成任务。最初,您站在
。
你手里拿着枪。当您处于某个顶点
时,您可以向地面上射击,然后将在顶点
建立一个门户。当工厂中有两个门户时,假设它们分别位于
和
处,则可以在
和
之间进行免费转换(就像连接长度为
的
和
的边一样)。
您的手边还有一个遥控器。它使您可以随时随地关闭门户网站(一次关闭一个门户网站,而不是一次关闭所有门户网站)。而且,最多可以有两个现有门户。因此,如果要在存在两个门户网站时创建另一个门户网站,则必须先使用控制器将其关闭,然后再创建。
您需要找到必须步行的最小距离才能完成所有
个任务。
输入描述:
第一行包含以空格分隔的三个正整数
,
,
。
接下来的m行中,每个包含三个整数
,
,
,表示连接顶点
和
的双向边,长度为
。接下来的
行中,每个行包含两个整数
,
,指示第
个任务的开始和结束。
,
,
该图保证已连接。
输出描述:
输出一个整数,表示最小距离。
样例:
样例输入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
思路:
题目大意:从点
出发,你要按顺序完成
个任务,每个任务有要求的起点和终点。途中你可以在所在的位置建立一个传送门,而同时只能用两个传送门存在,如果超过两个,则必须(远程)关闭任意一个传送门。
首先明确这道题用最短路和动态规划来做,
个任务都有起点终点,也就是说要走过
k个点。
数组需要记录
个状态:当前已经完成了
个任务,当前在
节点,传送门位置分别在
,
,也就是
------标准的暴力写法!
但是在途中你可以在你所在位置建立一个传送门,所以只需要记录远一点的那一个就行了,所以dp数组的维度就变成了三维:
而题目说了输入的节点是按
~
顺序的,所以不用记录当前节点的位置,于是dp数组的维度就变成了二维:
根据以上信息,我们可以写出状态转移的方程式:
从
直接走到
枚举
后放传送门的位置:从
走到放传送门的位置,然后传送到另一个传送门,走到
直接传送到另一个传送门,在从另一个传送门走到放传送门的位置,再走到
(有点复杂)
所以我们只要在没有传送门的情况下先对所有点跑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);
}