https://blog.csdn.net/liangzhaoyang1/article/details/52215276 原博客
原来好像是个dp题,不过我看了别人的博客使用贪心做的 复杂度(n^2)
题意:在一个数轴上有n个点,每个点有5个值x,a,b,c,d,你每次可以从一个点i跳跃到另外一个点j。
如果j在i的右边,则需要花费abs(x[i]-x[j])+c[i]+b[j]。
如果j在i的左边,则需要花费abs(x[i]-x[j])+d[i]+a[j],
一开始你位于s点,你的目的是遍历所有的点1遍并且最后停在e点,求最小花费.(注意:每个点最多只能遍历1遍)
题解:
初始化链:next[s] = e表示直接从起点s跳到终点e。
然后枚举其他所有的点,将它们一个一个插入到链中(寻找加入到链中的什么地方花费最低)
例如样例:
①:初始化:4->3
②:插入编号为1的点,显然1只能插入一个地方,插入后:4->1->3
③:插入编号为2的点,2可以插入两个地方(4和1中间或1和3中间),可以轻松算出插入4和1中间成本更低,所以
插入后:4->2->1->3
④:编号为3和4的点是起点和终点,跳过
⑤:插入编号为5的点,5可以插入三个地方,其中插入1和3中间成本更低,插入后:4->2->1->5->3
⑥:插入编号为6的点,……,插入后:4->2->1->6->5->3。
代码中的实现:
用 dis函数处理距离。
对 i=1~n按顺序 插,碰到s和e就跳过。 对每一个i,都找到一个最恰当的插的位置k,处理 k和前后的关系。
花费 用t表示,在计算t的时候 要减去原来dis(u,next[u]),这样后面直接就可以 ans+=minn。
1 #include<iostream> 2 #include<cstdio> 3 #include <cctype> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #include<string> 8 #include<cmath> 9 #include<set> 10 #include<vector> 11 #include<stack> 12 #include<queue> 13 #include<map> 14 using namespace std; 15 #define ll long long 16 #define mem(a,x) memset(a,x,sizeof(a)) 17 #define se second 18 #define fi first 19 const int INF= 0x3f3f3f3f; 20 const int N=3e5+5; 21 22 int n,s,e; 23 ll x[5005],a[5005],b[5005],c[5005],d[5005]; 24 ll net[5005]; 25 26 ll dis(int l,int r) 27 { 28 if(l<r) return abs(x[l]-x[r])+d[l]+a[r]; 29 if(l>r) return abs(x[l]-x[r])+c[l]+b[r]; 30 } 31 32 int main() 33 { 34 cin>>n>>s>>e; 35 for(int i=1;i<=n;i++) scanf("%lld",&x[i]); 36 for(int i=1;i<=n;i++) scanf("%lld",&a[i]); 37 for(int i=1;i<=n;i++) scanf("%lld",&b[i]); 38 for(int i=1;i<=n;i++) scanf("%lld",&c[i]); 39 for(int i=1;i<=n;i++) scanf("%lld",&d[i]); 40 41 net[s]=e; 42 ll ans=dis(s,e); 43 for(int i=1;i<=n;i++) 44 { 45 if(i==s||i==e) continue; 46 47 int u=s; 48 ll minn=1e18; 49 int k; 50 while(u!=e) 51 { 52 ll t=dis(u,i)+ dis(i,net[u])- dis(u,net[u]); 53 if(t<minn) 54 { 55 minn=t; 56 k=u; 57 } 58 u=net[u]; 59 } 60 ans+=minn; 61 //接下来把i插入这个线性结构中 62 net[i]=net[k]; //把i插在k的后面,k的next 就变成了 i的next 63 net[k]=i; //k的next变成 i 64 } 65 cout<<ans; 66 }