[CF704B] Ant Man

\(\text{Problem}:\)Ant Man

\(\text{Solution}:\)

首先容易考虑一个建图跑最短路的做法。但这显然就假了,原因是:无法保证路径长度;无法保证每个点至多被遍历一次。

但这提示我们如果存在一个能保证路径长度的做法,可能就可以解决本题。考虑初始状态只有 \(s,e\) 两个点。如果存在一种更新方式,使得每次插入一个全新的点都能保证局部最优,那么就解决了一开始做法的问题。

不难发现,若当前序列是 \(s,p_{1},p_{2},\cdot\cdot\cdot,p_{k},e\),则只要找到最优的位置插入 \(p_{k+1}\)​​ 即可。而这一定全局最优,利用反证法即可证明。时间复杂度 \(O(n^2)\)​。

\(\text{Code}:\)

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=5010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,S,E,ans,pre[N],nxt[N];
struct Node { int x,a,b,c,d; }q[N];
inline int Go(int i,int j)
{
	if(i>j) return q[i].x-q[j].x+q[i].c+q[j].b;
	return q[j].x-q[i].x+q[i].d+q[j].a;
}
signed main()
{
	n=read(), S=read(), E=read();
	for(ri int i=1;i<=n;i++) q[i].x=read();
	for(ri int i=1;i<=n;i++) q[i].a=read();
	for(ri int i=1;i<=n;i++) q[i].b=read();
	for(ri int i=1;i<=n;i++) q[i].c=read();
	for(ri int i=1;i<=n;i++) q[i].d=read();
	pre[E]=S, nxt[S]=E;
	ans=Go(S,E);
	for(ri int i=1;i<=n;i++)
	{
		if(i==S||i==E) continue;
		int pos=0, mi=1e18;
		int x=S;
		while(nxt[x])
		{
			int v=nxt[x];
			int w=Go(x,i)+Go(i,v)-Go(x,v);
			if(mi>w) pos=x, mi=w;
			x=nxt[x];
		}
		ans+=mi;
		pre[i]=pos, nxt[i]=nxt[pos];
		pre[nxt[pos]]=i, nxt[pos]=i;
	}
	int x=S;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-08-09 20:53  zkdxl  阅读(65)  评论(0编辑  收藏  举报