C. Travelling Salesman Problem DP
C. Travelling Salesman Problem DP
题目大意:
给你一张完全图,每一个点有两个值 \(a_i,c_i\) ,对于 \((u,v)\) 一条从 \(u\) 连向 \(v\) 的道路的距离是 \(max(c_u,a_v-a_u)\) ,问你从1出发,每一个点经过一次回到 1 的最短距离是多少?
题解:
- 首先确定因为每一个点只进入一次,出去一次,所以最后连成了一个环,所以起点其实是任意的。
- 因为距离是 \(max(c_u,a_v-a_u)\) 所以说最后的答案一定大于 \(c_i\) 之和,所以答案先加上 \(c_i\) ,所以距离就变成了 \(max(0,a_v-a_u - c_u)\)
- 把每一个点 \(a_i\) 看作这个点的高度,\(c_i\) 看作一个梯子
- 从最低点出发,如果达到了最高点,那么显而易见回到最低的距离就是已经在答案中的 \(c_i\)
- 所以我只需要求从最低点出发到达最高点的最小代价。
贪心的考虑这个怎么求,假设现在我希望到达的高度是 \(a_i\) ,那么我应该找前面 \([1,i-1]\) 中可以到达的最高的高度是多少也就是最大的 \(a_j+c_j(1\leq j\leq i-1)\) ,此时的到达 \(a_i\) 的代价就是 \(max(0,a_i-a_j-c_j)\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
struct node{
int a,c;
}e[maxn];
bool cmp(node a,node b){
return a.a < b.a;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int a,c;
scanf("%d%d",&a,&c);
e[i] = node{a,c};
}
sort(e+1,e+1+n,cmp);
ll maxs = e[1].a + e[1].c,ans = e[1].c;
for(int i=2;i<=n;i++){
ans += e[i].c;
if(e[i].a>maxs) ans += e[i].a - maxs;
maxs = max(maxs,1ll * e[i].a + e[i].c);
}
printf("%lld\n",ans);
return 0;
}