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;
}
posted @ 2021-04-08 20:38  EchoZQN  阅读(77)  评论(0编辑  收藏  举报