NOIP2008提高组复赛试题及题解 下载本文

procedure init;//预处理0~2000每个数需要的火柴棒数 var

i,j,k:longint; s:string; begin

for i:= 0 to maxn*2 do begin str(i,s); f[i]:=0;

for j:= 1 to length(s) do inc(f[i],num[s[j]]); end; end; begin flink; readln(n); init; ans:=0;

n:=n-4;//总火柴棒数减去'+'和'='所需的火柴棒数 for i:= 0 to maxn do//枚举A begin

if f[i]>=n then continue;//剪枝 for j:= 0 to maxn do//枚举B begin

if f[i]+f[j]>=n then continue;//剪枝 k:=i+j;

if f[i]+f[j]+f[k]=n then inc(ans);//符合条件,总数加一 end; end; write(ans); fclose; end.

参考程序2: program matches; var n:longint; begin

assign(input,'matches.in'); reset(input);

assign(output,'matches.out'); rewrite(output); read(n); n:=n-4; if n<9 then

begin

writeln(0); close(output); exit; end; case n of

9:writeln(1); 10:writeln(2); 11:writeln(8); 12:writeln(9); 13:writeln(6); 14:writeln(9); 15:writeln(29); 16:writeln(39); 17:writeln(38); 18:writeln(65); 19:writeln(88); 20:writeln(128); end;

close(output); end.

3. 传纸条

(massage.pas/c/cpp)

【问题描述】

小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。

在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。

还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度只和最大。现在,请你帮助小渊和小轩找到这样的两条路径。 【输入】

输入文件message.in的第一行有2个用空格隔开的整数m和n,表示班里有m行n列(1<=m,n<=50)。

接下来的m行是一个m*n的矩阵,矩阵中第i行j列的整数表示坐在第i行j列的学生的好心程度。每行的n个整数之间用空格隔开。 【输出】

输出文件message.out共一行,包含一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。

【输入输出样例】

message.in 3 3 0 3 9 2 8 5 5 7 0 message.out 34 【限制】

30%的数据满足:1<=m,n<=10 100%的数据满足:1<=m,n<=50

这道题和方格取数是一样的,只是状态的给出不同而已,典型的动态规划,我们可以把一来一回变成2次同时从左上到右下的过程,用f(i1,j1,i2,j2)表示两个同时分别到达(i1,j1)(i2,j2)的最大值,则转移方程为:

设x=max(f【i1-1,j1,i2-1,j2】,f【i1-1,j1,i2,j2-1】,f【i1,j1-1,i2-1,j2】,f【i1,j1-1,i2,j2-1】)

f【i1,j1,i2,j2】={ 0 i1=0或j1=0或i2=0 或j2=0

{ x+a【i1,j1】 i1*i2*j1*j2<>0 且 i1=i2,j1=j2 { x+a【i1,j1】+a【i2,j2】 i1*i2*j1*j2<>0 且 i1<>i2,j1<>j2

代码如下:

program message; var

f:array[0..51,0..51,0..51,0..51]of longint; map:array[0..100,0..100]of longint; n,m:longint; procedure init ; begin

assign(input,'message.in'); assign(output,'message.out'); reset(input); rewrite(output); end;

procedure prepare; var

i,j:longint; begin

readln(n,m);

for i:=1 to n do for j:=1 to m do begin

read(map[i,j]);

end; end;

procedure outit; begin

close(input) ; close(output); end;

procedure main; var

i,j,k,l:longint; begin

for i:=1 to n do for j:=1 to m do for k:=1 to n do for l:=1 to m do begin

if f[i-1,j,k-1,l]>f[i,j,k,l] then f[i,j,k,l]:=f[i-1,j,k-1,l];

if f[i-1,j,k,l-1]>f[i,j,k,l] then f[i,j,k,l]:=f[i-1,j,k,l-1];

if f[i,j-1,k-1,l]>f[i,j,k,l] then f[i,j,k,l]:=f[i,j-1,k-1,l];

if f[i,j-1,k,l-1]>f[i,j,k,l] then f[i,j,k,l]:=f[i,j-1,k,l-1];

f[i,j,k,l]:=f[i,j,k,l]+map[i,j];

if (i<>k)and(j<>l) then f[i,j,k,l]:=f[i,j,k,l]+map[k,l]; end;

writeln(f[n,m,n,m]); end;

begin init; prepare; main; outit; end.

var a:array[1..50,1..50] of integer;

f:array[1..100,1..50,1..50]of integer; m,i,j,n,total,k,x1,x2:integer;

function max(s1,s2,s3,s4:integer):integer; var s:integer; begin s:=s1;

if s2>s then s:=s2; if s3>s then s:=s3; if s4>s then s:=s4; max:=s; end;