题意: 你起初有一支军队,有 k 个士兵,现在,有 n 座城堡, 你若想占领第 i 座城堡,那你至少得有 ai 个士兵才能占领。
占领了 第 i 座城堡, 你可以扩大兵力, 得到 bi 的士兵。 然后你有两种方式使得防御你占领的城堡:
1、在你占领完的时候就留下一个士兵,防御它。
2、有m条小道,从ui -> vi; ui > vi; 你可以在占领完第 ui 座城堡的时候再 派一个士兵去 vi 防御 vi。
你必须防御了第 i 座城堡你才能得到 成就 ci。 现在问你, 在能占领 全部城堡的前提下, 最大的 成就是多少。
若不能占领全部城堡, 输出 -1;
解: 首先, 显而易见的, 对于每座城堡, 若它能在多个地方被防御,那肯定是选最晚的那个时候再来考虑是否对这座城堡进行防御。
不如, 若有一条小道 3 1; 那你肯定是在占领完第3座城堡的时候,再考虑是否对第1座城堡防御。
然后就有两种做法:
一、 dp
5000座塔,最多5000个士兵。 5000 * 5000 的dp, 完全没问题。
#include <bits/stdc++.h> #define LL long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF INT_MAX #define inf LLONG_MAX using namespace std; const int N = 5e3 + 5; int dp[N], a[N], b[N], c[N], last[N]; vector<int> G[N]; int main() { int n, k, m; scanf("%d %d %d", &n, &m, &k); mem(dp, -1); dp[k] = 0; rep(i, 1, n) { scanf("%d %d %d", &a[i], &b[i], &c[i]); last[i] = i; } rep(i, 1, m) { int u, v; scanf("%d %d", &u, &v); last[v] = max(last[v], u); } rep(i, 1, n) { G[last[i]].pb(c[i]); } rep(i, 1, n) { rep(j, 0, a[i] - 1) dp[j] = -1; dep(j, b[i], 5000) dp[j] = dp[j - b[i]]; for(auto v : G[i]) { rep(j, 0, 5000) { if(dp[j + 1] != -1) dp[j] = max(dp[j], dp[j + 1] + v); } } } int ans = -1; rep(i, 0, 5000) ans = max(ans, dp[i]); printf("%d ", ans); return 0; }
二、反悔贪心
对于每个城堡,我们都选择防御,然后,当出现士兵不够占领城堡的情况的时候,再贪心的把那些成就低的城堡放弃掉。
#include <bits/stdc++.h> #define LL long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF INT_MAX #define inf LLONG_MAX using namespace std; const int N = 5e3 + 5; int a[N], b[N], c[N], last[N]; vector< int > G[N]; priority_queue<int, vector<int>, greater<int> > Q; int main() { int n, m, k; scanf("%d %d %d", &n, &m, &k); rep(i, 1, n) { scanf("%d %d %d", &a[i], &b[i], &c[i]); last[i] = i; } rep(i, 1, m) { int u, v; scanf("%d %d", &u, &v); last[v] = max(last[v], u); } rep(i, 1, n) { G[last[i]].pb(c[i]); } int now = k; int res = 0; rep(i, 1, n + 1) { if(now < a[i]) { while(!Q.empty() && now < a[i]) { now++; res -= Q.top(); Q.pop(); } if(now < a[i]) { res = -1; break; } } now += b[i]; for(auto v : G[i]) { now--, res += v; Q.push(v); } } printf("%d ", res); return 0; }