在练习hackerearth的问题时,我遇到了以下问题(不是来自积极的比赛),并且经过多次尝试后未能成功解决问题。
钱德勒正在参加一场涉及N赛道的比赛 比赛。他想在这些有F量的赛道上驾驶他的旧车 初始燃料。在每场比赛结束时,钱德勒花费了si燃料和 获得一些钱,用来为他的汽车增加燃料量。同样,在任何阶段参加第一场比赛,钱德勒应该有 超过si量的燃料。他也可以参加一次比赛。 帮助钱德勒最大化他可以参加的比赛数量 他可以选择以任何顺序参加特定比赛。
我该如何处理这个问题。我的方法是按(ei-si)
进行排序,但我并不能确定燃料存在量超过种族所需的条件。
编辑我尝试使用以下算法解决但是它失败了,我也无法想到任何使算法失败的输入。请帮我弄清楚什么是错误的,或者在算法失败的地方给出一些输入。
Sort (ei-si) in non-increasing order;
start iterating through sorted (ei-si) and find first element such that fuel>=si
update fuel=fuel+(ei-si);
update count;
erase that element from list, and start searching again;
if fuel was not updated than we can't take part in any races so stop searching
and output count.
编辑以下是我要求的代码。
#include<iostream>
#include<vector>
#include<algorithm>
#include<list>
using namespace std;
struct race{
int ei;
int si;
int earn;
};
bool compareByEarn(const race &a, const race &b)
{
return a.earn <= b.earn;
}
int main(){
int t;
cin>>t;
while(t--){
vector<struct race> fuel;
int f,n;
cin>>f>>n;
int si,ei;
while(n--){
cin>>si>>ei;
fuel.push_back({ei,si,ei-si});
}
sort(fuel.begin(),fuel.end(),compareByEarn);
list<struct race> temp;
std::copy( fuel.rbegin(), fuel.rend(), std::back_inserter(temp ) );
int count=0;
while(1){
int flag=0;
for (list<struct race>::iterator ci = temp.begin(); ci != temp.end(); ++ci){
if(ci->si<=f){
f+=ci->earn;
ci=temp.erase(ci);
++count;
flag=1;
break;
}
}
if(!flag){
break;
}
}
cout<<count<<endl;
}
}
编辑如下面的答案中所述,上述贪婪的方法总是有效。所以现在任何替代方法都是有用的
答案 0 :(得分:2)
这是我的解决方案,由法官接受:
很明显,您消除有利可图的比赛的顺序无关紧要。 (只要你处理它们直到不能进入更有利可图的比赛。)
对于其余部分,我将首先证明如果存在解决方案,您可以按ei的降序执行相同的一组比赛,并且解决方案仍然可行。想象一下,我们有一个选择k种族的解决方案,让我们说这些k种族的起始和结束燃料值为s1,...,sk和e1,...,ek。让我成为第一个指数,其中ei&lt; ej(其中j = i + 1)。我们将证明我们可以在不违反任何约束的情况下交换i和i + 1。
很明显,交换i和i + 1不会破坏i之前或i + 1之后的任何约束,因此我们只需要证明如果我们将其顺序与种族i + 1交换,我们仍然可以执行竞赛i( j)的。在正常的顺序中,如果我们在比赛开始之前的燃料水平我是f,在比赛之后它将是f-si + ei,并且这至少是sj。换句话说,我们具有:f-si + ei> = sj,这意味着f-sj + ei> = si。但是,我们知道ei&lt; ej所以f-sj + ej> = f-sj + ei&gt; = si,因此在第i场比赛之前参加第j场比赛仍将至少为比赛i留下燃料。
从那里,我们实现了一个动态编程算法,其中d [i] [j]是我们可以参与的最大比赛数,如果我们只能使用比赛i..n并且我们从j单位的燃料开始。
这是我的代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 110;
const int maxf = 110*1000;
int d[maxn][maxf];
struct Race {
int s, e;
bool used;
inline bool operator < (const Race &o) const {
return e > o.e;
}
} race[maxn];
int main() {
int t;
for (cin >> t; t--;) {
memset(d, 0, sizeof d);
int f, n;
cin >> f >> n;
for (int i = 0; i < n; i++) {
cin >> race[i].s >> race[i].e;
race[i].used = false;
}
sort(race, race + n);
int count = 0;
bool found;
do {
found = 0;
for (int i = 0; i < n; i++)
if (!race[i].used && race[i].e >= race[i].s && race[i].s >= f) {
race[i].used = true;
count++;
f += race[i].s - race[i].e;
found = true;
}
} while (found);
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < maxf; j++) {
d[i][j] = d[i + 1][j];
if (!race[i].used && j >= race[i].s) {
int f2 = j - race[i].s + race[i].e;
if (f2 < maxf)
d[i][j] = max(d[i][j], 1 + d[i + 1][f2]);
}
}
}
cout << d[0][f] + count << endl;
}
return 0;
}
答案 1 :(得分:1)
您需要更改compareByEarn函数
bool compareByEarn(const race &a, const race &b)
{
if(a.earn == b.earn) return a.si < b.si;
return a.earn < b.earn;
}
以上比较意味着,选择收入更高(或损失更少)的赛道。但是如果有2条相同收益的音轨,则更喜欢需要更多燃料的音轨。
考虑示例
Initially fuel in the car = 4
track 1 : s = 2, e = 1
track 2 : s = 3, e = 2
track 3 : s = 4, e = 3
Expected answer = 3
Received answer = 2 or 3 depending on whether sorting algorithm is stable or unstable and the order of input\.
作为旁注:
同样,在任何阶段参加第一场比赛,钱德勒应该有 超过si量的燃料 应转换为
if(ci->si < f){ // and not if(ci->si<=f){
您可以检查我的观察是否正确,或者问题作者是否选择了不正确的句子来描述约束。
编辑
有了更多的推理,我意识到你只能用贪婪的方法做到这一点。
请考虑以下输入。
Initially fuel in the car = 9
track 1 : s = 9, e = 6
track 2 : s = 2, e = 0
track 3 : s = 2, e = 0
track 4 : s = 2, e = 0
Expected answer = 4
Received answer = 3