题意
给 (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;
}