POJ3614

/*
POJ 3614   
				   用快速排序会更快 这儿用的选择排序
奶牛美容:有C头奶牛日光浴,每头奶牛分别需要mini和maxi单位强度之间的阳光。
现有L种防晒霜,分别能使阳光强度稳定为SPF_i,其瓶数为cover_i。求最多满足多少头奶牛

个人理解:好奇葩的题目 奶牛的毛白长了^!^
一共C头牛 第i头牛 需要的阳光强度 ∈[mini,maxi]
有L种防晒霜 第i瓶能让阳光强度稳定在SPFi 且第i种有coveri瓶
问 最多能满足多少头牛
假设第i种防晒霜  对于这瓶防晒霜 可能会有多头牛 能适合即 SPFi ∈[mini,maxi]
那么这瓶最好给谁呢?
当然是给maxi小的牛 因为 maxi大的牛可能别的防晒霜也适合 即它的选择的空间大
即:
在满足minSPF的条件下,尽量把SPF小的防晒霜用在maxSPF小的奶牛身上,
因为maxSPF大的奶牛有更大的选择空间。用一个最小堆来维护
将奶牛按照阳光强度的最小值从小到大排序。
将防晒霜也按照能固定的阳光强度从小到大排序

从最小的防晒霜枚举,将所有符合  最小值小于等于该防晒霜的 奶牛的 最大值 放入最小堆之中。
然后堆中最小值先出
就可以将这些最大值中的最小的取出来。更新答案。
*/
# include <stdio.h> 
# define N 2500
void insert(int Tree[],int X);//最小堆 向Tree堆里插入X  tree[0]用来记录当前堆中数的个数
int DelMin(int Tree[]);//最小堆 删除最小值 tree[0]用来记录当前堆中数的个数
void paixu(int A[][N],int n);//以A[0]为比较依据 升序
void change(int *A,int *B);//交换A B的值
int main(){
    int C,L,i,num=0,SUM=0,maxSPF;
	int COW[2][N]={0},LFS[2][N]={0},tree[N]={0};
	scanf("%d %d",&C,&L);
	for(i=0;i<C;i++)
	  scanf("%d %d ",&COW[0][i],&COW[1][i]);//&COW[0][i],&COW[1][i] 分别存储牛的min max光
	for(i=0;i<L;i++)
    scanf("%d %d ",&LFS[0][i],&LFS[1][i]);//LFS[0]  LFS[1]分别存储防晒霜的 SPF 与瓶数
    paixu(COW,C);//按照牛的mini生序
	paixu(LFS,L);//按照化妆品的SPF升序
    for (i=0;i<L;i++)
	{                  //num为当前选中的满足可以涂防晒霜的牛
		while (num<C&&COW[0][num]<=LFS[0][i])//选出符合第i瓶防晒霜的牛
			insert(tree,COW[1][num++]);//进堆
        
		while (tree[0]&&LFS[1][i])
		{
			if (DelMin(tree)>=LFS[0][i])// “maxi”比这一瓶的上限大,说明这头奶牛可以被涂上防晒霜
			{
				++SUM;
				--LFS[1][i];
			}
		}
	}
	printf("%d\n",SUM);
    return 0;
}
void insert(int Tree[],int X)//向Tree堆里插入X  
{  
    int par,i=++Tree[0];  //插入X 后 Tree[0]+1  
    while(i>1)  //直到i不是根节点  
    {  
       par=i/2;  //父节点为par  
       if(Tree[par]<=X) break;//如果父节点满足最大堆的特性 则插入当前的位置即可  
       Tree[i]=Tree[par]; //否则调整堆 即位置上移  
       i=par;        
    }  
    Tree[i]=X;//插入新节点  
}  
int DelMin(int Tree[])//删除最小值  
{  
   int i=1,root=Tree[1],R,L,X=Tree[Tree[0]--];//X记录当前末尾节点 root为根 即为最小值  
   if(Tree[0]<0)  return -1;  
   while(i*2<=Tree[0])  
   {  
      L=i*2;  R=L+1;//Left Right 记录左右节点  
      if(R<=Tree[0]&&Tree[R]<Tree[L])L=R;  
      if(Tree[L]>=X) break;//如果所有的位置已经调整好 跳出循环  
      Tree[i]=Tree[L];//否则继续调整堆  
      i=L;  
   }   
   Tree[i]=X;  
   return  root;  
} 
void paixu(int A[][N],int n)//以A[0]为比较依据 升序
{
    int i,j,k;
	for(i=0;i<n-1;i++)
	{
	   k=i;
	   for(j=i+1;j<n;j++)
	      if(A[0][j]<A[0][k])
			   k=j;
		  if(k!=i)
		  {
		    change(&A[0][i],&A[0][k]);
            change(&A[1][i],&A[1][k]);
		  }
	}

}
void change(int *A,int *B)//交换A B的值
{
   int C=*A;
   *A=*B;
   *B=C;
}

  
  
Problem: 3614 User: aust182015302974
Memory: 232K Time: 0MS
Language: C Result: Accepted
# include <stdio.h>
# define N 2500
# define WEI 2
int C,L,i,num,SUM;
int COW[2][N],LFS[2][N];
int tree[N],Tree[2][N];
void INSERT(int Tree[][N],int S[]);
void DELMIN(int Tree[][N]);//删除最值 将最值存在S中
void insert(int Tree[],int X)//向最小堆中插入X
{
    int par,i=++Tree[0];            //插入X 后 Tree[0]+1
    while(i>1)                      //直到i不是根节点
    {
        par=(i>>1);                 //父节点为par
        if(Tree[par]<=X) break;     //将<=改为>=即改为最大堆了
        Tree[i]=Tree[par];          //否则调整堆 即位置上移
        i=par;
    }
    Tree[i]=X;                      //插入新节点
}
int Delmin(int Tree[])
{
    int i=1,L=2,root=Tree[1],X=Tree[Tree[0]--];
    while(L<=Tree[0])
    {
        L+=L<Tree[0]&&Tree[L+1]<Tree[L];
        if(Tree[L]>=X) break;
        Tree[i]=Tree[L];
        i=L;    L=i<<1;
    }
    Tree[i]=X;
    return  root;
}
int main(){
    int T[2];
    scanf("%d %d",&C,&L);
    for(i=0;i<C;i++)
    {
        scanf("%d %d",&T[0],&T[1]);
        INSERT(Tree,T);
    }
    i=0;
    while(Tree[0][0])
    {
    COW[0][i]=Tree[0][1];
    COW[1][i++]=Tree[1][1];
    DELMIN(Tree);
    }
    for(i=0;i<L;i++)
    {
        scanf("%d %d",&T[0],&T[1]);
        INSERT(Tree,T);
    }
    i=0;
    while(Tree[0][0])
    {
    LFS[0][i]=Tree[0][1];
    LFS[1][i++]=Tree[1][1];
    DELMIN(Tree);
    }
    for (i=0;i<L;i++)
    {
        while (num<C&&COW[0][num]<=LFS[0][i])
            insert(tree,COW[1][num++]);
        while (tree[0]&&LFS[1][i])
        {
            if (Delmin(tree)>=LFS[0][i])
            {
                ++SUM;
                --LFS[1][i];
            }
        }
    }
    printf("%d\n",SUM);
    return 0;
}
void INSERT(int Tree[][N],int S[]) //向最小堆Tree[]里插入元素S[WEI]
{
    int par,i=++Tree[0][0],j;  //插入X 后 Tree[0]+1
    while(i>1)  //直到i不是根节点
    {
       par=(i>>1);  //父节点为par
       if(Tree[0][par]<=S[0]) break;//如果父节点满足堆的特性 则插入当前的位置即可
       for(j=0;j<WEI;j++)                    //如果将Tree[0][par]<=S[0]改为Tree[0][par]>=S[0] 即为最大堆插入方式
       Tree[j][i]=Tree[j][par]; //否则调整堆 即位置上移
       i=par;
    }
    for(j=0;j<WEI;j++)
    Tree[j][i]=S[j];
}
void DELMIN(int Tree[][N])//删除最值 将最值存在S中
{
   int i=1,j,R,L=2,m=Tree[0][0]--,T[WEI];
   for(j=0;j<WEI;j++)
    T[j]=Tree[j][m];
   while(L<m)
   {
     L+= L<Tree[0][0]&&Tree[0][L+1]<Tree[0][L];
      if(Tree[0][L]>=T[0]) break;//并将 Tree[0][L]>=T[0]改为Tree[0][L]<=T[0]即为最大堆的删除代码
       for(j=0;j<WEI;j++)
      Tree[j][i]=Tree[j][L];//否则继续调整堆
      i=L;    L=i<<1;
   }
   for(j=0;j<WEI;j++)
   Tree[j][i]=T[j];  //调整好并赋值
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值