【求助】关于贪心算法的题,始终无法AC!

helloDesword 2014-02-03 09:21:45
题目网址:http://wikioi.com/problem/2079/

这次的题目依旧是贪心类别的,但是比较郁闷的是,没能最终写出AC的算法来,实在检查不出问题出在哪里

在OJ验证的话,只能通过一半的数据。

检查过排序算法,检查了最后数据的处理,应该没有越界的情况,我也实在想不出有什么诡异的数据来测试了。

代码里面有比较详细的注释,有问题的话随时口以交流。
/*
1、统计间隔信息,排序;
2、按照所给板子块数,切开;

要使木板总长度最少,就要使未盖木板的长度最大。
我们先用一块木板盖住牛棚,然后,每次从盖住的范围内选一个最大的空隙,以空隙为界将木板分成两块,重复直到分成m块或没有空隙。
*/
#include <stdio.h>
//快速排序算法
void quick(int *input,int l,int r)
{
if( l < r )
{
int i = l,j = r, x = input[l];
while(i<j)
{
while(i<j && input[j] <= x)// right to left to find the bigger than x
j--;
if(i < j)
input[i++] = input[j];
while(i<j && input[i] >= x)// left to right to find the minner than x
i++;
if( i< j)
input[j--]= input[i];
}
input[i] = x;
quick(input,l ,i-1);
quick(input, i+1 ,r);
}
}

int main()
{
int M,S,C;
int max_milk[210];
int dis[210];
scanf("%d %d %d",&M,&S,&C);
int i,j;
int len_dis;
for(i=0 ; i< C ; i++)
{
scanf("%d",&max_milk[i]);
}
//获取间隔值
for(i=0,j=0 ; i< C-1 ; i++)
{
if( max_milk[i+1]- max_milk[i] >1)
{
dis[j++] = max_milk[i+1] - max_milk[i]-1;
}
}
//排序
len_dis = j;
quick(dis,0,len_dis-1);

int count=0;
//按照木板数切割
//重复直到分成m块 i < M-1 或者没有空隙 i < len_dis
for(i=0 ; i < M-1 && i < len_dis; i++)
{
count += dis[i];
}
//去掉头,去掉尾,留下最后盖了板子的
printf("%d", S - (max_milk[0]-1) - (S-max_milk[C-1]) - count);
return 0;
}
...全文
308 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
helloDesword 2014-02-04
  • 打赏
  • 举报
回复
引用 3 楼 FancyMouse 的回复:
题目有说输入的C个数有序么?
题目没说输入有序
FancyMouse 2014-02-04
  • 打赏
  • 举报
回复
引用 8 楼 ls1160 的回复:
[quote=引用 6 楼 FancyMouse 的回复:] [quote=引用 4 楼 ls1160 的回复:] [quote=引用 3 楼 FancyMouse 的回复:] 题目有说输入的C个数有序么?
题目没说输入有序[/quote] 我的意思是你的代码必须在输入有序的时候才对……[/quote] 谢谢,我把前面也排序了之后,就能够测试通过了。只是,我的这个方法可能有点愚笨, 数据读入之前排序,处理之后再排序,然后按照贪心思想求解。 不知道大神有什么好的思路嘛?或者对于其中的处理有更好的解法? 谢谢哈~[/quote] 排个序又没啥……你这办法可以了。
helloDesword 2014-02-04
  • 打赏
  • 举报
回复
引用 6 楼 FancyMouse 的回复:
[quote=引用 4 楼 ls1160 的回复:] [quote=引用 3 楼 FancyMouse 的回复:] 题目有说输入的C个数有序么?
题目没说输入有序[/quote] 我的意思是你的代码必须在输入有序的时候才对……[/quote] 谢谢,我把前面也排序了之后,就能够测试通过了。只是,我的这个方法可能有点愚笨, 数据读入之前排序,处理之后再排序,然后按照贪心思想求解。 不知道大神有什么好的思路嘛?或者对于其中的处理有更好的解法? 谢谢哈~
helloDesword 2014-02-04
  • 打赏
  • 举报
回复
引用 6 楼 FancyMouse 的回复:
[quote=引用 4 楼 ls1160 的回复:] [quote=引用 3 楼 FancyMouse 的回复:] 题目有说输入的C个数有序么?
题目没说输入有序[/quote] 我的意思是你的代码必须在输入有序的时候才对……[/quote] 恩恩!是的,我也发现了,我现在修改了一下。正在测试。谢谢~
FancyMouse 2014-02-04
  • 打赏
  • 举报
回复
引用 4 楼 ls1160 的回复:
[quote=引用 3 楼 FancyMouse 的回复:] 题目有说输入的C个数有序么?
题目没说输入有序[/quote] 我的意思是你的代码必须在输入有序的时候才对……
helloDesword 2014-02-04
  • 打赏
  • 举报
回复
引用 2 楼 ALNG 的回复:
不用C++的话,用个堆来保留一定数量的最大的缺口也可以。现成的multiset, 不用可惜。


#include <stdio.h>
#include <set>

/* flag to see if a stall is occupied */
int occupied[200];

int check(int num_stall, int num_gap);

int main()
{
int board, cow, stall, t;
scanf("%d%d%d",&board, &stall, &cow);
for(int i=0; i<cow; ++i)
{
scanf("%d", &t);
occupied[--t]=1;
}

printf("%d",check(stall, --board));

return 0;
}

void get_range(int& beg, int& end, int num_stall)
{
for(int i=0; i<num_stall; ++i)
if(occupied[i])
{
beg=i;
break;
}
for(int i=num_stall-1; i>=0; --i)
if(occupied[i])
{
end=i;
break;
}
}

std::multiset<int> gaps;

void check_store(int cur_gap, int gap_count)
{
if(gaps.size()<(unsigned)gap_count)
gaps.insert(cur_gap);
else if(*gaps.begin()<cur_gap)
{
gaps.erase(gaps.begin());
gaps.insert(cur_gap);
}
}


int check(int num_stall, int num_gap)
{
int beg, end, len, cur_gap;
bool have_cow;

get_range(beg,end,num_stall);
len=end-beg+1; // naive length of board

// now we find within beg and end num_board-1 largest gap
// this can be done with a single scan
cur_gap=0;
have_cow=true;
for(int i=beg+1;i<end; ++i)
{
switch( (occupied[i]<<1)+have_cow)
{
case 0: // neither this and prev has cow
++cur_gap;
break;
case 1: // this is not occupied, but prev is occupied
have_cow=false;
cur_gap=1;
break;
case 2: // this occupied, but prev is empty
check_store(cur_gap, num_board);
//cur_gap=0;
have_cow=true;
break;
}
}
for(std::multiset<int>::iterator i=gaps.begin(); i!=gaps.end(); ++i)
len-=*i;
return len;
}


对如下的测试数据,我的结果是401:
10 500 120
3
4
6
8
14
15
16
17
21
25
26
27
30
31
40
41
42
43
100
37
96
77
55
3
74
66
25
68
350
463
489
496
424
303
325
317
398
408
416
438
85
76
98
96
12
55
63
78
96
102
466
385
386
475
112
363
354
425
225
226
217
238
233
239
247
248
246
244
250
258
265
266
267
269
270
271
272
277
279
285
286
287
289
290
291
292
295
296
297
299
310
311
312
313
315
447
448
459
438
437
433
426
424
423
433
432
410
400
375
376
377
379
381
383
384
385
386
387
392
393

谢谢你的回复~至于你说的multiset 和线性排序,我没学过,得自己学下了。
1、你上面的check_store(cur_gap, num_board);中应该是num_gap吧;
2、你的测试数据应该294,和我后来修改后的一样,
3、放到OJ里面测试的话,有点问题;

孩皮妞野 2014-02-03
  • 打赏
  • 举报
回复
不用C++的话,用个堆来保留一定数量的最大的缺口也可以。现成的multiset, 不用可惜。

#include <stdio.h>
#include <set>

/* flag to see if a stall is occupied */
int occupied[200];

int check(int num_stall, int num_gap);

int main()
{
	int board, cow, stall, t;
	scanf("%d%d%d",&board, &stall, &cow);
	for(int i=0; i<cow; ++i)
	{
		scanf("%d", &t);
		occupied[--t]=1;
	}
	
	printf("%d",check(stall, --board));
	
	return 0;
}

void get_range(int& beg, int& end, int num_stall)
{
	for(int i=0; i<num_stall; ++i)
		if(occupied[i])
		{
			beg=i;
			break;
		}
	for(int i=num_stall-1; i>=0; --i)
		if(occupied[i])
		{
			end=i;
			break;
		}
}

std::multiset<int> gaps;

void check_store(int cur_gap, int gap_count)
{
	if(gaps.size()<(unsigned)gap_count)
		gaps.insert(cur_gap);
	else if(*gaps.begin()<cur_gap)
	{
		gaps.erase(gaps.begin());
		gaps.insert(cur_gap);
	}
}


int check(int num_stall, int num_gap)
{
	int beg, end, len, cur_gap;
	bool have_cow;
	
	get_range(beg,end,num_stall);
	len=end-beg+1; // naive length of board
	
	// now we find within beg and end num_board-1 largest gap
	// this can be done with a single scan
	cur_gap=0;
	have_cow=true;
	for(int i=beg+1;i<end; ++i)
	{
		switch( (occupied[i]<<1)+have_cow)
		{
		case 0: // neither this and prev has cow
			++cur_gap;
			break;
		case 1: // this is not occupied, but prev is occupied
			have_cow=false;
			cur_gap=1;
			break;
		case 2: // this occupied, but prev is empty
			check_store(cur_gap, num_board);
			//cur_gap=0;
			have_cow=true;
			break;
		}		
	}
	for(std::multiset<int>::iterator i=gaps.begin(); i!=gaps.end(); ++i)
		len-=*i;
	return len;
}
对如下的测试数据,我的结果是401: 10 500 120 3 4 6 8 14 15 16 17 21 25 26 27 30 31 40 41 42 43 100 37 96 77 55 3 74 66 25 68 350 463 489 496 424 303 325 317 398 408 416 438 85 76 98 96 12 55 63 78 96 102 466 385 386 475 112 363 354 425 225 226 217 238 233 239 247 248 246 244 250 258 265 266 267 269 270 271 272 277 279 285 286 287 289 290 291 292 295 296 297 299 310 311 312 313 315 447 448 459 438 437 433 426 424 423 433 432 410 400 375 376 377 379 381 383 384 385 386 387 392 393
孩皮妞野 2014-02-03
  • 打赏
  • 举报
回复
确实是个贪心问题。似乎不需要排序,只要线性扫描一遍就可以了。我再瞅瞅。
FancyMouse 2014-02-03
  • 打赏
  • 举报
回复
题目有说输入的C个数有序么?

69,336

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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