思路:二分答案
分析:
1 首先我们遇到这类无从下手的题目的时候,我们首先应该考虑的就是利用二分答案,其它我们无从下手。
2 对于这道题,我们只要二分然后逼近答案即可。
3 这里对二分的时候返回的是right而不是mid做一个解释
我们观察二分的形式可以看到while(left <= right){},那么我们知道在得到答案之前的一步肯定是left = mid = right ;假设这个时候judge(mid)满足那么left = mid+1 ,mid = right ,既然满足就有ans = mid,所以这个时候返回right = mid正确;如果judge(mid)不满足那么right = mid-1, mid = left, 答案肯定不是mid那只能是right。所以可以得出二分的时候返回的是right。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1010;
const int N = 25;
struct components{
char type[N];
char name[N];
int price;
int qulity;
};
components c[MAXN];
int n , budge;
bool judge(int x){
int i , j , sum = 0;
for(i = 0 ; i < n ;){
int Min = 2147483647;
int pos = -1;
for(j = i ; j < n && !strcmp(c[i].type , c[j].type) ; j++){
if(c[j].qulity >= x && Min > c[j].price){
pos = j;
Min = c[j].price;
}
}
if(pos == -1) return false;
sum += Min;
i = j;
}
return sum <= budge ? true : false;
}
int solve(int Min , int Max){
int left , right , mid;
left = Min , right = Max;
while(left <= right){
mid = (left+right)>>1;
if(judge(mid))
left = mid+1;
else
right = mid-1;
}
return right;//返回的是right
}
int main(){
int Case;
int Min , Max;
scanf("%d" , &Case);
while(Case--){
scanf("%d%d" , &n , &budge);
Min = 2147483647 , Max = 0;
for(int i = 0 ; i < n ; i++){
scanf("%s %s %d %d" , c[i].type , c[i].name , &c[i].price , &c[i].qulity);
Min = min(Min , c[i].qulity);
Max = max(Max , c[i].qulity);
}
int ans = solve(Min , Max);//这里爱原来的数组中求大于等于它的最小值,怕二分到的答案没在原数组中
for(int i = 0 ; i < n ; i++){
if(c[i].qulity >= ans)
ans = min(ans , c[i].qulity);
}
printf("%d\n" , ans);
}
return 0;
}