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;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/12167546.html