cf1504E - Travelling Salesman Problem

E - Travelling Salesman Problem

传送门

题意: 有n个点,每个点有两个值a和c,从一个点i到另一个点j的花费是 max ⁡ c i , a j − a i \max{c_i, a_j - a_i} maxci,ajai, 问将所有点遍历一次且仅遍历一次的最小花费

思路: 可以发现从一个a值较高的点向a值较低的点移动的时候花费就是ci,

c是永远省不掉的,于是花费就会变成所有的c的和以及从 a m i n a_{min} amin a m a x a_{max} amax的点的花费,于是减少a部分的花费

将点按a从小到大排序,然后按照1到n标号(,问题就变成了从1上升到n的最少的额外花费(因为从标号大的到标号小的是没有额外花费的)

d p [ i ] = m i n { d p [ j ] − a [ j ] − c [ j ] } dp[i] = min\{dp[j] - a[j] - c[j]\} dp[i]=min{dp[j]a[j]c[j]} + a[i]

dp[n] 就是从1往上到n的最小花费,发现还是有些细节(当我在口胡(…嗯

参考了下blog

code:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll N = 2e5 + 10;

bool vis[N];

struct node {
    ll a, c;
} mp[N];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll n;
    cin >> n;

    for (ll i = 1; i <= n; ++i) {
        cin >> mp[i].a >> mp[i].c;
    }

    sort(mp + 1, mp + n + 1, [](node x, node y) {
        return x.a < y.a;
    });

    ll pos = 1, ans = 0;

    ll h = mp[pos].a + mp[pos].c;

    for (ll i = 2; i <= n; ++i) {
        if (h < mp[i].a + mp[i].c) {
            ans += max(mp[i].a - mp[pos].a, mp[pos].c);
            h = mp[i].a + mp[i].c;
            vis[pos] = 1;
            pos = i;
        }
    }

    ans += mp[n].c;
    for (ll i = n - 1; i; --i) {
        if (vis[i]) continue;
        ans += mp[i].c;
    }
    cout << ans << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值