帖子来了!

emailed 2008-04-24 03:34:25
There are n piles of stones on the ground. The size of each pile is a0, a1, a2 ... an. Now you can take away at most K stones from one pile or several piles. Your task is to write a program to minimize the difference between the largest size pile and the smallest one which are left after taken?
Input
There are several test cases in the input data. The first line contains the number of test cases. There are two lines in each test case. The first line contains two number n and K (1 ≤ n ≤ 50, 1 ≤ K ≤ 50) which are described above. The second line contains a sequence of n elements denoting the size of each pile which will not exceed 50.
Output
Output the minimum difference between the largest size pile and the smallest one.
Sample Input

3
2 1
2 5
2 2
2 5
5 3
2 2 5 5 5

Sample Output

2
0
2

Hint: In the second case, you can take away all the stones of pile 0 to make only one pile left. Therefore, the difference can be minimized.
...全文
156 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
emailed 2008-04-27
  • 打赏
  • 举报
回复
原来这题数据小可以枚举阿 。。晕。
  • 打赏
  • 举报
回复
刚才看了你的代码,清楚你的思路了。应该说前面我们说的本质上其实是一致的(往自己脸上贴贴金,呵呵)

1楼里的两处笔误:
“那么可以直接拿走数目最小的n-i堆,即先拿走ai,a2,a(n-i);”=>“那么可以直接拿走数目最小的n-i堆,即先拿走a1,a2,...,a(n-i);”
“假设aj剩下cj个石子,那么拿之前ak的数目肯定比拿之后的ai的石子多”=>“假设aj剩下cj个石子,那么拿之前ak的数目肯定比拿之后的cj的石子多”

tailzhou思路敏捷,代码能力超强,佩服佩服:)
tailzhou 2008-04-25
  • 打赏
  • 举报
回复
实际上,假设最优方案最后剩下i堆石子,那么拿走数目最少的n-i堆(假设这n-i堆总共j个石子)后,
其余的k-j个石子依次从剩下的这i堆中数目最大的堆里取,取完k-j个后分两种情况:
1)如果最后能取到这i堆中数目最小的堆(数目最小的堆可能不止一个,只要取到其中一个就算),那么肯定可以取少于k个石子使得差异为0;
2)如果最后不能取到这i堆中数目最小的堆,那么肯定不可能差异为0,这样取的越多,差异越小;


tailzhou 2008-04-25
  • 打赏
  • 举报
回复
我的思路没什么问题,只要考虑一些边界条件就可以了;
以下是一个accepted的代码
353823 2008-04-25 11:07:51 Accepted 2962 C 1.0K 0'00.00" 604K tailzhou


#include <stdio.h>
#include <stdlib.h>

void sort(int *a,int n)
{
int i,j,k;
for (i=0;i<n ;i++ )
{
int min=i;
for (j=i+1; j<n; j++)
{
if (a[j]<a[min]) min=j;
}
if (i!=min)
{
k=a[i];
a[i]=a[min];
a[min]=k;
}

}
}

int main()
{
int t;
int num[50];
int dif[50];

scanf("%d", &t);
while (t--)
{
int n,k,r;
int i,j;
scanf("%d %d", &n,&k);
i=0;
while (i<n)
{
scanf("%d", &num[i]);
i++;
}

sort(num,n);

if (n>1) dif[n-1]=num[n-1]-num[n-2];
for (i=n-2;i>0 ; i--)
{
dif[i]=(num[i]-num[i-1])*(n-i)+dif[i+1];
}

r=num[n-1]-num[0];
for (i=0;i<n && k>=0; i++)
{
int tmp;

j=n-1;
while (dif[j]<k && j>0) j--;

if (j>i)
{
tmp=num[j-1]+(dif[j]-k)/(n-1-j+1)-num[i];
if ((dif[j]-k) % (n-1-j+1)>0) tmp++;
}
else tmp=0;

if (tmp<0) tmp=0;

if (tmp<r) r=tmp;

k-=num[i];
}

printf("%d\n",r);
}
return 0;
}

  • 打赏
  • 举报
回复
“Now you can take away at most K stones from one pile or several piles”
最多能拿K个。那言外之意是不是说拿走的数目可以少于K个?tailzhou说的好像不是这个意思吧。


减少最大堆和最小堆差距的途径无非有两种:
一.减少最大堆的值(注意最大堆可能有多个,每堆都减掉一些才管用);
二.增加最小堆的值——只能通过拿空小数目的石头堆来实现。
当然,还可以双管齐下。


将石堆做一个计数:数量为q[1]的有c[1]堆,数量为q[2]的有c[2]堆,…,数量为q[h]的有c[h]堆
(这里q[1]<q[2]<…<q[h],且c[1]+c[2]+…+c[h]==n)
我们来考察两个函数:Up(t)和Down(t),其中:
Up(t)表示将最小堆抬升到t需要取走的石头数目,设这个函数的定义域为集合U;
Down(t)则表示将最大值降到t需要取走的石头数目,假设这个函数的定义域为集合D。

显然,U中的元素只可能是q[1],q[2],...,q[h],且
Up(q[1])=0;
Up(q[2])=q[1]*c[1]
Up(q[3])=q[1]*c[1]+q[2]*c[2]
……
Up(q[h])=q[1]*c[1]+q[2]*c[2]+……+q[h-1]*c[h-1]
先来看看是否有Up[q[h]]<=K,如果这个不等式成立,那么尽管将小数量的石堆拿空,只剩下最大的那些堆就可以了,差值为0,一定是最小的;如果不成立,我们接着往下忙活。

Down(t)这个函数稍微复杂一些。
Down(q[h])=0
Down(q[h-1])=Down(q[h])+(q[h]-q[h-1])*c[h]
Down(q[h-2])=Down(q[h-1])+(q[h-1]-q[h-2])*(c[h]+c[h-1])
……
Down(q[1])=Down(q[2])+(q[2]-q[1])*(c[h]+c[h-1]+…+c[2])
实际上,Down(t)函数是单调递减的,我们只需要看K落在上面给出的哪两个数值之间.
假设有Down(q[i])<=k<Down(q[i-1]),
受K的限制,集合D中最小值也只能是 D1=q[i]-(K-Down(q[i]))/(c[h]+c[h-1]+…c[i])
集合D为[D1,q[h]]范围里的连续整数。

有了上面的准备之后,题目要求的值就是
Value=min{b-a | a属于U,b属于D,a<=b,且Up(a)+Down(d)<=K}
emailed 2008-04-25
  • 打赏
  • 举报
回复
这个描述我实在是看了费劲阿 。。。郁闷ing
  • 打赏
  • 举报
回复
只是描述起来比较罗嗦,实现的时候并不是特别复杂,看tailzhou的代码就知道了。
emailed 2008-04-25
  • 打赏
  • 举报
回复
无语了,好像好复杂啊 。。。。
emailed 2008-04-24
  • 打赏
  • 举报
回复
没看懂你说的啊。。。
emailed 2008-04-24
  • 打赏
  • 举报
回复
那个i指的是?
tailzhou 2008-04-24
  • 打赏
  • 举报
回复
对n堆按照石子的数目排序,不妨假设序列为a1,a2,a3,...an

假设存在某一最好的方案,该方案的结构结剩有i堆,那么可以直接拿走数目最小的n-i堆,即先拿走ai,a2,a(n-i);
因为如果剩有的i堆中有“数目最小的n-i堆”的其中一个,假设为aj,j<=n-i,那么肯定有某个ak,k>n-i被拿走;
那么将该方案做如下调整:
假设aj剩下cj个石子,那么拿之前ak的数目肯定比拿之后的ai的石子多;
那么总可以将ak剩下cj个石子,并全部拿走aj ,这样总的剩的堆数跟每堆的数量都保持不变;
即调整后的方案也是最优的方案;

依据以上的结论;
对剩余堆的数目为0-N的每一种情况分别判断;

比如对剩余i堆的方案,;
1)先拿走最小的n-i堆,那么数目最小的堆就是a(n-i+1),对该i堆石子可以建立一个最大堆的数据结构;
2)从数目最大的堆拿石子,调整最大堆;
3)直到总共拿走了k个石子;

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧