UVa 11292 Dragon of Loowater
题意
有n条龙,有m个勇者,每个勇者只能消灭能力值小于等于自身的龙,每个勇者消灭一条龙之后要付给等于他能力值的金钱,每个勇者有且只能雇佣一次,问怎样雇佣勇者才能消灭龙且花费最少,若不能消灭,则输出Loowater is doomed!
思路
我一开始的思路
对于每个条恶龙,将其从大到小排序,在勇者当中用二分搜索查找第一个大于等于条龙能力值的勇者,没有就直接结束,有的话记录这个勇者的花费,同时删除这条龙和这个勇者,再考虑下一条龙…知道所有龙考虑完或者没有勇者了。
最后如果龙的数量为0,就输出花费,不为就输出Loowater is doomed!。
思路评价
这种思路AC了,不过实现极其复杂,使用了优先队列去存龙,使用vector去存勇者。二分查找,vector的删除元素,总之就是各种xjb操作。
而且实现效率不高,代码编写要求难
AC代码1
#include<bits/stdc++.h>
using namespace std;
void solve(void)
{
int n,m;
while(scanf("%d%d",&n,&m))
{
priority_queue<int,vector<int>,greater<int> >a;
vector<int>b;
if(n==0&&m==0) break;
for(int i = 0 ; i < n ; i++)
{
int temp;
cin>>temp;
a.push(temp);
}
for(int j = 0 ; j < m ; j++)
{
int temp;
cin>>temp;
b.push_back(temp);
}
sort(b.begin(),b.end());
int ans = 0;
int flag = 0;
while(!b.empty())
{
int aim = a.top();
a.pop();
auto now = lower_bound(b.begin(),b.end(),aim) - b.begin();
//cout<<now<<endl;
if(b[now]==*b.end()&&aim!=*b.end())
{
cout<<"Loowater is doomed!"<<endl;
flag = 1;
break;
}
else
{
vector<int>::iterator it = b.begin() + now;
ans+=*it;
b.erase(it);
}
if(a.empty()) break;
}
if(flag==0)
{
if(a.empty()) cout<<ans<<endl;
else cout<<"Loowater is doomed!"<<endl;
}
}
}
int main(void)
{
solve();
return 0;
}
标程的思路
把龙和人的能力值分别存储,然后同时从小到大排序,从最小的开始比较,设定两个标志量i和j,i代表当前比较的龙的编号,j表示当前比较的人的标号。
如果人的能力值大于等于龙的能力值,i++,j++,记录花费。
否则,人的编号j++,移动到下一个人再去比较。
直到人的编号等于人数或者龙的编号等于龙数则退出。
如果最后龙的编号等于龙数则说明所有的龙都被消灭了,输出花费就可。
否则输出Loowater is doomed!
思路评价
简化了思维方式,从而简化了代码。
思路均是从对于每条恶龙,找到第一个比他能力值大的勇者。
但是这个是从头开始一个一个比对,能力小的勇者永久的被遗弃,效率更高。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 20005
int a[maxn];
int b[maxn];
void solve(void)
{
int n,m;
while(scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
for(int i = 0 ; i < n ; i++) scanf("%d",&a[i]);
for(int i = 0 ; i < m ; i++) scanf("%d",&b[i]);
int i = 0,j = 0;
sort(a,a+n);
sort(b,b+m);
long long sum = 0;
for(i = 0 ; i < m ; i++)
{
if(b[i] >= a[j]) {sum+=b[i];j++;}
if(j==n) break;
}
//cout<<j<<endl;
if(j==n) printf("%lld\n",sum);
else printf("Loowater is doomed!\n");
}
}
int main(void)
{
solve();
return 0;
}
相比起来…..
没有必要使用二分查找,因为本身就可以从头开始线性查找,而且对于每条龙,没有打败他的勇者,那么能力值小于没有打败他的勇者就肯定也打败他,之前的比较可以继续使用,二分查找不但也需要排序,其实也浪费了一部分查询结果。
没必要使用优先队列,应为数组就足够实现。也并不需要自动排序,完全就是花里胡哨的写法。
Don’t trouble troubles till trouble troubles you!
所能学到的
由于这次的复杂思路,反而巩固了一波STL的知识点。
less 和 greater
less<int>()
greater<int>()
less和greater 都是是头文件xfunctional中定义的两个结构。
// TEMPLATE STRUCT greater
template<class _Ty>
struct greater
: public binary_function<_Ty, _Ty, bool>
{ // functor for operator>
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator> to operands
return (_Left > _Right);
}
};
// TEMPLATE STRUCT less
template<class _Ty>
struct less
: public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
greater是从大到小排序的一种写法
less是从小到大排序的一种写法
vector当中的erase()
erase有两种用法:
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
删除一个元素,那么我们可以这样写:
vector<int>::iterator it = b.begin() + now;///找到这个元素的位置。
b.erase(it);///删除它。