You play a strategic video game (yeah, we ran out of good problem legends). In this game you control a large army, and your goal is to conquer castles of your opponent.html
Let’s describe the game process in detail. Initially you control an army of
warriors. Your enemy controls n castles; to conquer the
-th castle, you need at least ai warriors (you are so good at this game that you don’t lose any warriors while taking over a castle, so your army stays the same after the fight). After you take control over a castle, you recruit new warriors into your army — formally, after you capture the
-th castle,
warriors join your army. Furthermore, after capturing a castle (or later) you can defend it: if you leave at least one warrior in a castle, this castle is considered defended. Each castle has an importance parameter
, and your total score is the sum of importance values over all defended castles. There are two ways to defend a castle:
if you are currently in the castle
, you may leave one warrior to defend castle
;
there are
one-way portals connecting the castles. Each portal is characterised by two numbers of castles
and
(for each portal holds
). A portal can be used as follows: if you are currently in the castle u, you may send one warrior to defend castle
.
Obviously, when you order your warrior to defend some castle, he leaves your army.web
You capture the castles in fixed order: you have to capture the first one, then the second one, and so on. After you capture the castle
(but only before capturing castle i+1) you may recruit new warriors from castle
, leave a warrior to defend castle
, and use any number of portals leading from castle
to other castles having smaller numbers. As soon as you capture the next castle, these actions for castle
won’t be available to you.数组
If, during some moment in the game, you don’t have enough warriors to capture the next castle, you lose. Your goal is to maximize the sum of importance values over all defended castles (note that you may hire new warriors in the last castle, defend it and use portals leading from it even after you capture it — your score will be calculated afterwards).
Can you determine an optimal strategy of capturing and defending the castles?app
The first line contains three integers ) — the number of castles, the number of portals and initial size of your army, respectively.ide
Then lines follow. The -th line describes the -th castle with three integers , and — the number of warriors required to capture the -th castle, the number of warriors available for hire in this castle and its importance value.svg
Then lines follow. The -th line describes the -th portal with two integers and , meaning that the portal leads from the castle to the castle . There are no two same portals listed.优化
It is guaranteed that the size of your army won’t exceed 5000 under any circumstances (i. e. ).ui
If it’s impossible to capture all the castles, print one integer
.
Otherwise, print one integer equal to the maximum sum of importance values of defended castles.this
按顺序占领 全部城堡,能够选择在该城堡刚被占领时留下一个士兵得到权值,也能够经过 单向边来在后面占领该城堡得到权值。spa
以前的作法过于混乱(甚至我本身都以为像是瞎蒙的),所以借鉴了其余神犇的题解仔细思考后发现可使用反悔型贪心来作这道题。
思路为:
一路扫过去,每次都假定留守全部可留守的点,发现当前的士兵不够则从已留守的点中选取权值最小的放弃留守。
依然是基于 靠后留守更优 策略,预处理出每一个点可留守的集合,遍历到该点直接将可留守的所有push到已留守集合中,再遍历下一个点。 在遍历点过程当中发现士兵不够,pop已留守集合,若是pop空了还不够,说明游戏失败。
代码一块儿放到后面了。自我感受注释够详细了。
能不能占领完城堡很好判断,只须要每次都取光士兵而不留守扫一遍,若是这种状况下都有没法占领的城堡,那必定无法占领完。
若是要留守城堡
,那么必定是在最后留守最好。
所以能够开一个
数组,
标记要留守
的最晚位置是哪里。
如今开始思考留守的实质:若是在位置
留守,就是使区间
的可用士兵数量减小
。
咱们要保证这段位置的可用士兵数量减小
以后还能占领全部的城堡。
因而有:
inline bool check(const int &p) { for(int i = p;i<=n;++i) if(a[i] + 1 > d[i])//d[i]表明占领i前的可用士兵数量 return false; return true; }
随后思考要怎么选择留守哪些城堡。能够发现,贪心地留守权值大的城堡必定是最优的。
由于留守一个城堡影响的是
整个区间,咱们能够讨论:
若是
,且
,即
的权值比
大,有3种状况:
1.[last[i1]+1,n]的区间所有减去2个士兵后依然能占领全部城堡。那么就是
和
都留守的状况,此时操做顺序不会影响结果。
2.[last[i1]+1,last[i2]]的区间减去1个士兵能知足,[last[i2]+1,n]减去2个士兵能知足,因为咱们先处理权值大的,处理完
后还能处理
,也能够获得正确答案。
3.[last[i1]+1,n]的区间减去1个士兵能知足,此时
与
只能选择一个,那么确定是选取
好。
选取
和
的区别就在于
这段区间,是否会对结果形成影响呢?
咱们将选择
看作消耗
和
内的士兵数量。
假定有一个
的选择,,且
,若是
,很显然选择
和
是等效的。
若是
,那么选取
的代价比选取
更大且得利更少,所以此时先选择
能够保证总体更优。
若是
之间,若选
后还能选
则确定选
,若选
后不能选
,那么选
后确定也不能选
,但
,所以可能状况下仍是选
更好。
另外,若
且
,很显然此时选择i1比选择i2好。
可能写的有点乱……
#include <cstdio> #include <algorithm> template <typename T> inline T max(const T &a,const T &b){return a>b?a:b;} inline char nc() { static char buf[1000000],*p1 = buf,*p2 = buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++; } void read(int &r) { static char c;r=0; for(c=nc();c>'9'||c<'0';c=nc()); for(;c>='0'&&c<='9';r=(r<<1)+(r<<3)+(c^48),c=nc()); } int n,m,k; int last[5001];//last[i]保存i点最晚能在哪里被派兵守卫 int a[5001],b[5001],c[5001],d[5001];//d[i]表明占领i前到达i这里的兵力 int q[5001]; bool cmp(const int &a,const int &b) { return c[a] > c[b]; } inline bool check(const int &p) { for(int i = p;i<=n;++i) if(a[i] + 1 > d[i]) return false; return true; } int main() { read(n); read(m); read(k); int now = k;//如今兵力 for(int i = 1;i<=n;++i) { read(a[i]); read(b[i]); read(c[i]); d[i] = now; if(now < a[i]) { printf("-1"); return 0; } now += b[i];//顺便判断是否能占领全部城堡,也就是判断每次取完兵可否一路所有占领 q[i] = last[i] = i; } int u,v; for(;m;--m) { read(u); read(v); last[v] = max(last[v],u); } std::sort(q+1,q+1+n,cmp);//按照贡献值排序 int ans = 0; for(int i = 1;i<=n;++i) { if(check(last[q[i]] + 1)) { for(int j = last[q[i]] + 1;j<=n;++j) --d[j]; ans += c[q[i]]; } } printf("%d",ans); return 0; }
这里是反悔贪心的代码:
#include <cstdio> #include <queue> #include <vector> using namespace std; //读入优化 inline char nc() { static char buf[100000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++; } template <typename T> inline void read(T &r) { static char c;r = 0; for (c = nc(); c > '9' || c < '0'; c = nc()); for (; c >= '0' && c <= '9'; r = (r << 1) + (r << 3) + (c ^ 48), c = nc()); } const int maxn = 5e3 + 10; int n, m, k, ans; int a[maxn], b[maxn], c[maxn]; int last[maxn]; //last[i]记录i最后能在哪里被留守 priority_queue<int, vector<int>, greater<int>> q; vector<int> defback[maxn]; //存储该点能够向前留守什么点 int main() { read(n); read(m); read(k); for (int i = 1; i <= n; ++i) { read(a[i]); read(b[i]); read(c[i]); last[i] = i; //初始化 } int u, v; for (; m; --m) { read(u); read(v); last[v] = last[v] > u ? last[v] : u; //取更大者,由于越后留守必定越好 } for (int i = 1; i <= n; ++i) defback[last[i]].push_back(i); for (int i = 1; i <= n; ++i) { while (k < a[i] && !q.empty()) //不够的话,从已留守的城堡中取出权值最小的放弃,即反悔 ++k, q.pop(); //defended[q.top()] = false; 事实上并不须要对是否已经留守作标记,由于全部点最多会被判断留守一次,也就是最多被标true false一次 if (k < a[i]) //若是取完仍是不够,那没办法了,输出-1 goto fail; //占领当前点 k += b[i]; //往前留守,这里不用考虑当前点,由于当前点要么也在vector中,要么在后面能够被留守 for (vector<int>::iterator it = defback[i].begin(); it != defback[i].end(); ++it) --k, q.push(c[*it]); //能够直接所有push到留守集合中,等后面再反悔,不用考虑会不会让k<0 } //最后一步后还要判断k是否大于0进行一次反悔 while (k < 0 && !q.empty()) ++k, q.pop(); if (k < 0) goto fail; while (!q.empty())//统计已留守点的权值和 ans += q.top(), q.pop(); printf("%d", ans); return 0; fail: puts("-1"); return 0; }