二分搜索——TOJ 3029 Assemble

    我是第一次用这种二分+搜索匹配做题,其实我也不确定就一定是叫这个,不过我是这样觉得。做这个题目花了我很多的精力,开始的时候是想用DP做的,但怎么都想不通怎么用DP来做,如果不是每种组件有多个还要好点,加上每个组件还可以有多种选择而且quality的取值范围又那么大,所以,想来想去就算DP用得成,以我的DP水平估计也是超时。

    整来整去整出了这种方法,最大的优势是通过题目中的巨大quality突显出来的,不用从小到大每个都遍历到,而是用二分查找的思想,将原先1000000000次的循环转变成O(logN)的查找,节约了大量的时间。具体而言,就是用二分查找的办法确定一个要达到的最大quality,然后看能不能实现,如果不能实现的话,就将quality变小(用二分);如果能够达到,则同样将quality取大(还是二分),这样结束的时候就可以得到最大的quality。但是数据有个郁闷的地方,就是对于同一种组quality也并不是随price的增加而增加的,之前我都一直理所当然地认为是这样,结果就是能够通过测试数据,但怎么都过不了。后来仔细观察给出的测试数据,发现其中就有这种状况,于是将排序的部分作一下修改,结果就过了。

AC Code:

#include <iostream>
#include <string>
#include <algorithm>
//#include <fstream>
using namespace std;

struct Node{
    char type[21];
    int price, qual;
}infor[1001];
int array[1001], num, budget, comNum;

bool compare(Node a, Node b)
{	//The same compent are closed, and the quality are descend sort
    if(strcmp(a.type, b.type) > 0)
        return true;
    else if(strcmp(a.type, b.type) < 0)
        return false;
    else{
        if(a.qual > b.qual)
            return true;
        else
            return false;
    }
}

int getBest()
{
    int ans = 0, low = 0, high = 1000000000, mid, usedm;
    bool flag;
    int j, tmp, lowprice;
    infor[0].price = 0;
    while(low <= high){
        mid = (low+high)/2;
        usedm = 0;
        flag = true;
        for(int i = 1; i <= comNum; i++){
            j = array[i-1]+1;	lowprice = infor[j].price;	tmp = j;
            while((j <= array[i]) && (infor[j].qual >= mid)){
                //avoid the situation that higher price with lower quality
                if(lowprice > infor[j].price){
                    tmp = j;
                    lowprice = infor[j].price;
                }
                j++;
            }
            j = tmp;
            if(infor[j].qual < mid){
                high = mid-1;
                flag = false;
                break;
            }
            if((budget-usedm) < lowprice){
                high = mid-1;
                flag = false;
                break;
            }
            usedm += lowprice;
        }
        if(flag && (mid >= ans)){
            ans = mid;
            low = mid+1;
        }
    }
    return ans;
}

int main()
{
//    ifstream fin ("data.in");
    int tcase;
    char name[21];
//    fin>>tcase;
    cin>>tcase;
    while(tcase--){
//        fin>>num>>budget;		
    	scanf("%d%d", &num, &budget);
        for(int i = 1; i <= num; i++)
            scanf("%s%s%d%d", infor[i].type, name, &infor[i].price, &infor[i].qual);
//            fin>>infor[i].type>>name>>infor[i].price>>infor[i].qual;
        sort(infor+1, infor+num+1, compare);
        strcpy(name, "");
        comNum = 0;
        array[0] = 0;
        for(int i = 1; i <= num; i++){
            if(!strcmp(name, infor[i].type))
                array[comNum]++;
            else{
                comNum++;
                array[comNum] = array[comNum-1]+1;
                strcpy(name, infor[i].type);
            }
        }
        cout<<getBest()<<endl;
    }
    return 0;
}


<!-- -->#include  < iostream >
#include 
< string >
#include 
< algorithm >
// #include <fstream>
using   namespace  std;

struct  Node{
    
char  type[ 21 ];
    
int  price, qual;
}infor[
1001 ];
int  array[ 1001 ], num, budget, comNum;

bool  compare(Node a, Node b)
{    
// The same compent are closed, and the quality are descend sort
     if (strcmp(a.type, b.type)  >   0 )
        
return   true ;
    
else   if (strcmp(a.type, b.type)  <   0 )
        
return   false ;
    
else {
        
if (a.qual  >  b.qual)
            
return   true ;
        
else
            
return   false ;
    }
}

int  getBest()
{
    
int  ans  =   0 , low  =   0 , high  =   1000000000 , mid, usedm;
    
bool  flag;
    
int  j, tmp, lowprice;
    infor[
0 ].price  =   0 ;
    
while (low  <=  high){
        mid 
=  (low + high) / 2 ;
        usedm 
=   0 ;
        flag 
=   true ;
        
for ( int  i  =   1 ; i  <=  comNum; i ++ ){
            j 
=  array[i - 1 ] + 1 ;    lowprice  =  infor[j].price;    tmp  =  j;
            
while ((j  <=  array[i])  &&  (infor[j].qual  >=  mid)){
                
// avoid the situation that higher price with lower quality
                 if (lowprice  >  infor[j].price){
                    tmp 
=  j;
                    lowprice 
=  infor[j].price;
                }
                j
++ ;
            }
            j 
=  tmp;
            
if (infor[j].qual  <  mid){
                high 
=  mid - 1 ;
                flag 
=   false ;
                
break ;
            }
            
if ((budget - usedm)  <  lowprice){
                high 
=  mid - 1 ;
                flag 
=   false ;
                
break ;
            }
            usedm 
+=  lowprice;
        }
        
if (flag  &&  (mid  >=  ans)){
            ans 
=  mid;
            low 
=  mid + 1 ;
        }
    }
    
return  ans;
}

int  main()
{
    
// ifstream fin ("data.in");
     int  tcase;
    
char  name[ 21 ];
    fin
>> tcase;
    
// cin>>tcase;
     while (tcase -- ){
        
// fin>>num>>budget;        
           scanf( " %d%d " & num,  & budget);
        
for ( int  i  =   1 ; i  <=  num; i ++ )
               scanf(
" %s%s%d%d " , infor[i].type, name,  & infor[i].price,  & infor[i].qual);
            
// fin>>infor[i].type>>name>>infor[i].price>>infor[i].qual;
        sort(infor + 1 , infor + num + 1 , compare);
        strcpy(name, 
"" );
        comNum 
=   0 ;
        array[
0 =   0 ;
        
for ( int  i  =   1 ; i  <=  num; i ++ ){
            
if ( ! strcmp(name, infor[i].type))
                array[comNum]
++ ;
            
else {
                comNum
++ ;
                array[comNum] 
=  array[comNum - 1 ] + 1 ;
                strcpy(name, infor[i].type);
            }
        }
        cout
<< getBest() << endl;
    }
    
return   0 ;
}

    这个题目给我的收获应该说是巨大的,以前在DP的时候遇到这种超大型的数据,我就不知道怎么办了,因为我只会简单的DP,也就自然地还是把它当作状态的一维,结果就很容易的超时了。这个题目的这种二分+搜索匹配的思想给了我很大的提示。

    但通过这个题目,也注意到了一些问题,无论怎样,还是要先仔细观察一下给出的测试数据,如果待到做完了才发现理解错题意或者有地方没注意到,那就亏大了。

你可能感兴趣的:(J#)