2020牛客暑期多校训练营(第五场)——A Portal

2020牛客暑期多校训练营(第五场)——A Portal

题目描述

You are now in a big factory. The factory could be recognized as a graph with n vertices and m edges. Every edge has its length. You have k missions to do. The ith mission is going to vertex ai, picking a block and then sending it to vertex bi . You should complete the missions in the order from 1st to kth. Initially you are standing at vectex 1.

You have a gun in your hand. When you are at some vertex u, you could shoot the gun at the ground, and then a portal will be built at vertex u. When there are two portals in the factory, assuming they are at u and v, you could transfer between u and v with no cost(just like an edge connecting u and v with length 0).

You also have a remote controller in your hand. It allows you to close a portal whenever you want and wherever you are(closing one portal at a time, not all portals at the same time). What’s more, there could be at most two existing portals. So if you want to create another portal when there exists two, you must use your controller to close one before you create.

You need to find the minimum distance you have to walk in order to complete all k missions.

输入描述

在这里插入图片描述

输出描述

Output one integer indicating the minimum distance.

样例输入

输入1

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

输入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

输入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

样例输出

输出1

5

对输出1的说明

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

28

输出3

16

题目大意

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

题解

设f[i][p]表示当前已经完成了前i个任务,当前正在c[i]上,传送门的位置在p。
可以证明,只需要3种转移,就可以覆盖所有情况:
1.直接从c[i]走到c[i+1]
2.枚举走到c[i+1]之后,传送门的位置变为了哪个节点,设这个节点是q。第二种转移是从c[i]走到q,在q设置传送
门,从q传送到p,再从p走到c[i+1]
3.第三种转移是从c[i]传送到p,从p走到q,在q设置传送门,最后从q走到c[i+1]

AC代码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
long long f[1010][505],d[1010][505],a[1010],n,m,k,x,y,z;
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>m>>k;
	memset(d,0x16,sizeof(d));
	memset(f,0x16,sizeof(f));
	for(int i=1;i<=n;i++)d[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y>>z;
		d[x][y]=d[y][x]=min(d[x][y],z);
	}//联通d[x][y],d[y][x](有多条路取最小值) 
	a[1]=1;
	for(int i=1;i<=n;i++)cin>>a[2*i]>>a[2*i+1];
	for(int k=1;k<=n;k++)
	{ 
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{ 
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
			} 
		} 
	} //联通d[i][j]取最小值。 
	for(int i=1;i<=n;i++)f[1][i]=d[1][i];//从1到i最小步数 
	for(int i=2;i<=2*k+1;i++)
	{
		for(int p=1;p<=n;p++)
		{
            f[i][p]=min(f[i][p],f[i-1][p]+d[a[i]][a[i-1]]);
            for(int q=1;q<=n;q++)
			{
                f[i][q]=min(f[i][q],f[i-1][p]+d[p][q]+d[q][a[i]]);
                f[i][q]=min(f[i][q],f[i-1][p]+d[a[i-1]][q]+d[p][a[i]]);
            }
        }
	}
    long long ans=f[2*k+1][1];
    for(int i=1;i<=n;i++)
        ans=min(ans,f[2*k+1][i]);
    cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/cxkdad/article/details/107592635