E - Travelling Salesman Problem
题意: 有n个点,每个点有两个值a和c,从一个点i到另一个点j的花费是 max c i , a j − a i \max{c_i, a_j - a_i} maxci,aj−ai, 问将所有点遍历一次且仅遍历一次的最小花费
思路: 可以发现从一个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的最小花费,发现还是有些细节(当我在口胡(…嗯
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;
}