【测试】11月9日的测试

整体分析

1(集合删数)

题目大意

问题描述:

一个集合有如下元素:1是集合元素;若P是集合的元素,则2 * P +1,4*P+5也是集合的元素,取出此集合中最小的K个元素,按从小到大的顺序组合成一个多位数,现要求从中删除M个数位上的数字,使得剩下的数字最大,编程输出删除前和删除后的多位数字。

注:不存在所有数被删除的情况`

输入格式:

输入的仅一行,K,M的值,K,M均小于等于30000。

输出格式:

输出为两行,第一行为删除前的数字,第二行为删除后的数字。

样例输入:

5 4

样例输出:

137915

95

用到的数据结构,算法

贪心,字符串处理,打表一类的……

正确分析

首先要产生这个集合,可以打表,也可以先有现用的数组里的数字产生。每次的元素只有可能有已有的元素通过两种运算产生,所以我们每次产生两个元素,取其小者即可。接下来就是贪心策略的使用了,显然要去找比较大的元素,那么我们为了满足删除一部分数之后,剩下的数能满足要求,那么每个数的取值是被限制在产生的数的一个确定的区间中的。每次在选取一个数后,我们就将区间起点移动到这个数的位置,区间的尾端只和选取的数的个数有关。那么通过n-m次的选取,我们就会得到一个最大值

错误原因

打表时出现错误。打的表不够大,没有选取目标元素。

贪心策略不是很优秀,效率较低。

反思

在打表时,有的时候要涉及到排序 ,那么就需要将打表的范围扩大到要求的范围之外,然后再选取需要的元素。

贪心策略就是一种积累,既然贪心,就要追求高效

var
  biao:array[0..600000] of longint;
  s,numb:ansistring;
  n,i,last,k,m,j,a,b,l,w,t:longint;
  max:char;

function min(a,b:longint):longint;
begin
  if a<b then exit(a);
  exit(b);
end;


begin
  assign(input,'number.in');reset(input);
  assign(output,'number.out');rewrite(output);
  readln(k,m);
  i:=1;
  j:=1;
  biao[1]:=1;
  for l:=2 to k do
  begin
    a:=2*biao[i]+1;
	b:=4*biao[j]+5;
	if a<b then
	begin
	  biao[l]:=a;
	  inc(i);
	end
	else if a=b then
	begin
	  biao[l]:=a;
	  inc(i);
	  inc(j);
	end
	else
	begin
	  biao[l]:=b;
	  inc(j);
	end;
  end;
  numb:='';
  for i:=1 to k do
  begin
    str(biao[i],numb);
	s:=s+numb;
  end;
  n:=length(s);
  writeln(s);
  if n=m then
  begin
    writeln('');
	close(input);
	close(output);
	halt;
  end;
  if m=0 then
  begin
    writeln(s);
	close(input);
	close(output);
	halt;
  end;
 // t:=0;
  w:=0;
  for t:=1 to n-m do
  begin
    max:='0';
    for i:=w+1 to min(m+t,n) do
	  if s[i]>max then
	  begin
  	    max:=s[i];
		w:=i;
	  end;
	write(max);
  end;
  close(input);
  close(output);
end.


2(durle)

题目大意

对任意给定的m(m∈N+)和n(n∈N+),满足m<n,构造一初始集合:P={x|m≤x≤n,x∈N+}(m,n≤100)。现定义一种d规则如下:若存在a∈P,且存在K∈N+ ,K>1,使得K´a∈P,则修改P为:P=P-{y|y=s´a,s∈N+ } ,并称该d规则具有分值a。现要求编制一个程序,对输入的m,n值,构造相应的初始集合P,对P每应用一次d规则就累加其相应的分值,求能得到最大累加分值的d规则序列,输出每次使用d规则时的分值和集合p的变化过程。

输入格式:

输入仅一行,M,N的值。

输出格式:

输出每次使用d规则时的分值和集合p的变化过程(即变化后的集合内所有的数,每个数用空格隔开),注意D后面有个空格,冒号后面有个空格。如果没有一次可以变化就输出0。

样例输入:

(1)

1 10

(2)

56 57

样例输出:

(1)

5 : 1 2 3 4 6 7 8 9

4 : 1 2 3 6 7 9

2 : 1 3 7 9

3 : 1 7

1 :

(2)

0

用到的数据结构,算法

模拟,贪心

正确分析

正确分析题目要求和样例,我们知道,对于给定的一个区间里的数,如果存在一个数是另外几个数的约数,我们就继续进行操作。那么如过一个数拥有的倍数的个数和另一个数相同,那么我们选择较大的那个元素。如果倍数的个数不同,那么我们选择倍数个数较少的元素。

错误原因

没有选择正确的贪心策略,没有正确的理解题意

反思

仔细分析题意根据题目的信息,来推导算法,有的时候,找不到合适的算法就按照题目的要求模拟就可以。

program liukee;
var
  a:array[0..100] of longint;
  f:array[0..100] of longint;
  m,n,i,sum,min,j,k:longint;
  flag:boolean;
begin
    assign(input,'drule.in');
    reset(input);
    assign(output,'drule.out');
    rewrite(output);
  readln(m,n);
  if n=m+1 then
  begin
    writeln(0);
    close(input);
	close(output);
	halt;
  end;
  for i:=m to n do
    f[i]:=true;
  flag:=false;
  sum:=n-m+1;
  while sum>0 do
  begin
    fillchar(a,sizeof(a),0);
	min:=maxlongint;
	for i:=m to n do
	  if f[i] then
	    for j:=m to n do
		  if f[j] then
		  if (i<>j)and(j mod i=0) then
		    inc(a[i]);
	for i:=n downto m do
	  if (a[i]<>0)and(a[i]<min)then
	  begin
	    min:=a[i];
		k:=i;
	  end;
	if min=maxlongint then break;
	flag:=true;
	write(k,' : ');
	for i:=m to n do
	  if (i mod k=0)and(f[i]) then
	  begin
	    f[i]:=false;
		dec(sum);
	  end;
	for i:=m to n do
	  if f[i] then write(i,' ');
	writeln;
  end;
  if flag=false then writeln(0);
  close(input);
  close(output);
end.
    

 

posted @ 2010-11-09 16:16  liukee  阅读(250)  评论(0编辑  收藏  举报