POJ 1928

 

鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。
鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图1)。有经验的多多一眼就能看出,每棵花生植株下的花生有多少。为了训练多多的算术,鲁宾逊先生说:“你先找出花生最多的植株,去采摘它的花生;然后再找出剩下的植株里花生最多的,去采摘它的花生(也就是说,即便20不能被采摘,也不能采摘小于20的花生,最后的时间可能会剩余,这是不同于NYOJ 106贪心背包问题的);依此类推,不过你一定要在我限定的时间内回到路边。”
 
我们假定多多在每个单位时间内,可以做下列四件事情中的一件:
1.从路边跳到最靠近路边(即第一行)的某棵花生植株;
2.从一棵植株跳到前后左右与之相邻的另一棵植株;
3.采摘一棵植株下的花生;
4.从最靠近路边(即第一行)的某棵花生植株跳回路边。
现在给定一块花生田的大小和花生的分布,请问在限定时间内,多多最多可以采到多少个花生?注意可能只有部分植株下面长有花生,假设这些植株下的花生个数各不相同。
 
  
【输入】
n  输入第一行包括三个整数,M, N和K,用空格隔开;表示花生田的大小为M * N(1 <= M, N <= 20),多多采花生的限定时间为K(0 <= K <= 1000)个单位时间。接下来的M行,每行包括N个非负整数,也用空格隔开;第i + 1行的第j个整数Pij(0 <= Pij <= 500)表示花生田里植株(i, j)下花生的数目,0表示该植株下没有花生。
【输出】
n 输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。
 
 
//类似背包问题的解决办法 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
typedef struct DATA
{
    int num;
    int x,y;//花生位置 
}DATA; 
/* 
结构体的话,用一维数组
否则二维数组,这道题来说,因为要排序 且
涉及到位置的转换,结构体更方便 
*/ 
DATA ch[3000];
int cmp(const void *a,const void *b)
{ 
    //((DATA *)b),外层的括号是必须的     
    return ((DATA *)b)->num-((DATA *)a)->num;
}
int main()
{
    int i,j,k,T;
    int m,n,k0,cnt,total,temp;
    scanf("%d",&T);
    while(T--)
    {
        cnt=0;//耗费时间 
        total=0;//花生数目         
        temp=0;//路到节点移动时间 
        memset(ch,0,sizeof(ch));
        scanf("%d%d%d",&m,&n,&k0);
        /*
        for(i=0;i<m*n;i++)
        {
           scanf("%d",&ch[i].num);
           下面的两行大错特错,横坐标会0,1,2……m-1循环变化,实际应是000000,11111…… 
           ch[i].x=i%m;
           ch[i].y=i%n;
        }
        */ 
        k=0;
        for(i=0;i<m;i++)
            for(j=0;j<n;j++)
            {
                ch[k].x=i;
                ch[k].y=j;
                scanf("%d",&ch[k++].num);
            }  
        qsort(ch,m*n,sizeof(DATA),cmp);//sizeof(DATA),不是int 
        /* 
        printf("\n\n\n");
        k=0;
        for(i=0;i<m;i++)
        {  
             for(j=0;j<n;j++)
                 printf("%d %d  %d  ",ch[k++].num,ch[k].x,ch[k].y);
            printf("\n");
        }
        */
        //类似背包问题的解决办法 
       for(i=0;ch[i].num!=0&&cnt<k0;i++)//第一个条件防止死循环(如果采摘完了,仍有时间) 
       {
            //printf("total=%d      cnt=%d\n",total,cnt);
            if(i!=0)         
                temp=abs(ch[i+1].x-ch[i].x)+abs(ch[i+1].y-ch[i].y);
            if(0==i)
            {
                if(2*(ch[i].x+1)+1>k0)
                    break;
                else if(2*(ch[i].x+1)+1==k0)
                {       
                    total+=ch[i].num;
                       break;
                }
                else
                {
                    cnt+=ch[i].x+1+1;//1为本次采摘时间 
                    total+=ch[i].num;
                    temp=abs(ch[1].x-ch[0].x)+abs(ch[1].y-ch[0].y);
                    if(cnt+temp+1+ch[i+1].x+1<=k0)//是否采摘下个节点 ,第一个1为下次采摘时间 
                    {
                        total+=ch[i+1].num;
                        cnt+=temp+1;
                    }
                    else
                        break;
                }
             } 
             else if(cnt+temp+1+ch[i+1].x+1<=k0)//是否采摘下个节点 
             {
                   total+=ch[i+1].num;
                   cnt+=temp+1;
             }
             else
                  break;   
        }          
        printf("%d\n",total);
    }
    system("pause");
    return 0;
}
            
            
                
                 
        
            
        
        
    

 

posted @ 2012-07-27 17:50  加拿大小哥哥  阅读(1233)  评论(0编辑  收藏  举报