CodeForces 705D. Ant Man 贪心+链表

传送门

题意

\(n\) 个点,已知坐标 \(x_i\),参数 \(a_i,b_i,c_i,d_i\)。可以根据坐标和参数计算从一个点跳到另一个点的花费。
要求从 \(s\) 点到 \(t\) 点且经过所有仅一次的最小总花费。

思路

第一次接触这样贪心的题,感觉很巧妙
做一个链表,最开始为 \(s\)->\(e\)
然后从 \(1\)\(n\) 依次插入链表,(\(s\)\(e\) 除外)
至于插到哪个位置,因为 \(k\) 插到 \(i\)->\(j\) 中,花费增加为 \(len[i][k]+len[k][j]-len[i][j]\)
那么找这个最小的增加花费的位置就是要插入的位置了

代码

不想写链表,于是直接写了个vector,反正时间复杂度都是 \(O(n^2)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const LL INF=0x3f3f3f3f3f3f3f3f;
int n,s,e,x[5010],a[5010],b[5010],c[5010],d[5010];
LL len[5010][5010],ans;
vector<int> vec;


int main(){
	scanf("%d%d%d",&n,&s,&e);
	for(int i=1;i<=n;i++) scanf("%d",&x[i]);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	for(int i=1;i<=n;i++) scanf("%d",&c[i]);
	for(int i=1;i<=n;i++) scanf("%d",&d[i]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			if(i==j) continue;
			if(j<i) len[i][j]=(LL)abs(x[i]-x[j])+c[i]+b[j];
			else len[i][j]=(LL)abs(x[i]-x[j])+d[i]+a[j];
		}
	vec.push_back(s);
	vec.push_back(e);
	ans=len[s][e];
	for(int i=1;i<=n;i++){
		if(i==s||i==e) continue;
		int pos=1;
		LL temp=ans-len[vec[0]][vec[1]]+len[vec[0]][i]+len[i][vec[1]];
		for(int j=2;j<vec.size();j++){
			LL tp=ans-len[vec[j-1]][vec[j]]+len[vec[j-1]][i]+len[i][vec[j]];
			if(tp<temp) pos=j,temp=tp;
		}
		ans=ans-len[vec[pos-1]][vec[pos]]+len[vec[pos-1]][i]+len[i][vec[pos]];
		vec.insert(vec.begin()+pos,i);
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2020-01-08 16:53  BakaCirno  阅读(145)  评论(0编辑  收藏  举报