鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。
鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图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;
}