当前位置:文档之家› NoiP2003提高组复赛试题分析

NoiP2003提高组复赛试题分析

第一题:神经网络【试题分析】一、题意分析1、任务描述:从输入层开始,各节点按照传递公式,一层一层向下传递。

输出输出层中信号大于零的节点编号和信号大小。

(节点编号由小到大)如果没有满足条件的编号则输出NULL。

信号传递公式:∑∈-=Ei jijjiiUCWC),(公式中的Wji(可能为负值)表示连接j号神经元和i号神经元的边的权值。

当Ci大于0时,该神经元处于兴奋状态,否则就处于平静状态。

当神经元处于兴奋状态时,下一秒它会向其它神经元传递信号,信号的强度为Ci。

2、输入:两个整数n(1≤n≤20)和p。

n表示节点的个数;p表示有向边的条数。

下面n行表示1-n号节点的状态和阈值。

下面p行表示有向边及其权值。

3、输出:输出输出层状态大于零的神经元编号和状态,并且按照编号有小到大顺序输出!若输出层的神经元最后状态小于等于0,则输出NULL。

二、问题分析1、题目中给出每层神经元只向下一层的神经元输出信息,只从上一层神经元接受信息。

所以不必进行拓扑排序,一层一层的向下传递信号即可。

输出最后一层中信号大于零的节点编号。

2、可以建立一个队列,将输入层节点入队。

3、取队首节点出队,寻找此节点有向边,如果有有向边:1)则记录此节点不是输出层;2)再判断此节点信号大于零则向下传递信号,将指向的节点入队(防止重复入队)。

再出队再传递,直至全部出队。

注意:1)输入层可以是输出层。

2)信号传递公式中只减一次U[i]。

【程序清单】Program network;ConstInName='network.in';OutName='network.out';MM=100;VarInFile,OutFile:Text;C,U:Array[1..MM] Of LongInt;Map:Array[1..MM,1..MM] Of LongInt;Flag:Array[1..MM,1..MM] Of Boolean;IsOut:Array[1..MM] Of Boolean;Queue:Array[1..MM] Of LongInt;N,P,i,Int1,Int2,Head,Rear:LongInt;IsInQueue:Array[1..MM] Of Boolean;IsNull:Boolean;BeginAssign(InFile,InName);Reset(InFile);ReadLn(InFile,N,P);For i:=1 To N Do ReadLn(InFile,C[i],U[i]); FillChar(Flag,SizeOf(Flag),False);For i:=1 To P Do BeginRead(InFile,Int1,Int2);ReadLn(InFile,Map[Int1,Int2]);Flag[Int1,Int2]:=True;End;Close(InFile);FillChar(IsOut,SizeOf(IsOut),True);FillChar(IsInQueue,SizeOf(IsInQueue),False); Head:=1; Rear:=1;For i:=1 To N Do BeginIf C[i]>0 Then BeginQueue[Rear]:=i;Inc(Rear);IsInQueue[i]:=True;EndElse C[i]:=-U[i];End;While Head<Rear Do BeginFor i:=1 To N DoIf Flag[Queue[Head],i] Then BeginIf C[Queue[Head]]>0 Then BeginInc(C[i],Map[Queue[Head],i]*C[Queue[Head]]);If Not IsInQueue[i] Then BeginQueue[Rear]:=i;Inc(Rear);IsInQueue[i]:=True;End;End;IsOut[Queue[Head]]:=False;End;Inc(Head);End;Assign(OutFile,OutName);Rewrite(OutFile);IsNull:=True;For i:=1 To N DoIf IsOut[i] ThenIf C[i]>0 Then BeginWriteLn(OutFile,i,' ',C[i]);IsNull:=False;End;If IsNull Then WriteLn(OutFile,'NULL');Close(OutFile);End.第二题:侦探推理【试题分析】一、题意分析1、任务描述:M个人参加游戏,每人提供一句或多句证言,共P句证言。

其中N个人始终说假话,其余的人始终说真话。

请你通过证言判断出谁是罪犯。

证词中出现的其它话,都不列入逻辑推理的内容。

2、输入:第一行有三个整数,M(1≤M≤20)、N(1≤N≤M)和P(1≤P≤100):M是参加游戏的明明的同学数,N是其中始终说谎的人数,P是证人的综述。

接下来M行,每行是明明的一个同学的名字(英文字母组成,没有空格,全部大写)。

往后有P行,每行开始是某个同学的名字,紧跟着一个冒号和一个空格,后面是一句证词,符合前表中所列格式,证词每行不会好过250个字符。

输入中不会出现连续的两个空格,而且每行开头和结尾也没有空格。

3、输出:如果你的程序能确定谁是罪犯,则输出他的名字;如果程序判断出不止一个人可能是罪犯,则输出Cannot Determine;如果程序判断出没有人可能成为罪犯,则输出Impossible。

二、问题分析1、根据题意可知可以利用枚举法完成。

枚举罪犯和今天是星期几。

满足N 个人始终说谎话和M-N个人始终说真话的条件,就可以确定罪犯。

2、首先利用字符串操作将证言转化成计算机可表示的信息。

1)定义Guilty:Array[1..MM,1..MM] Of Integer;{-1..1}FillChar(Guilty,SizeOf(Guilty),0) 初值为0Guilty[i,j]=-1:表示第i个人说第j个人不是罪犯Guilty[i,j]= 1:表示第i个人说第j个人是罪犯其中包含Guilty[i,i]即第i个人说自己是不是罪犯注意:Guilty不可以自相矛盾。

2)定义WhatDay:Array[1..MM,1..7] Of Boolean;FillChar(WhatDay,SizeOf(WhatDay),False)WhatDay[i,j]:=True :表示第i个人说过j是星期几3、枚举罪犯和星期几,判断每句证言是真是假,统计说真假证言的人数。

注意:有可能某人又说过真话,又说过假话。

4、根据题目要求输出罪犯编号或Cannot Determine或Impossible。

【程序清单】Program logic;ConstInName='logic.in';OutName='logic.out';MM=20;DayState:Array[1..7] Of String=('is Monday. #','is Tuesday. #','is Wednesday. #','is Thursday. #','is Friday. #','is Saturday. #','is Sunday. #');cImpossible=-1;cCannotDetermine=-2;VarInFile,OutFile:Text;M,N,P:Integer;Name:Array[1..MM] Of String;Guilty:Array[1..MM,1..MM] Of Integer;{-1..1}WhatDay:Array[1..MM,1..7] Of Boolean;i,j:Integer;IsGuilty:Array[1..MM] Of Boolean;Ans,AnsC:Integer;Procedure Print(ID:Integer);BeginAssign(OutFile,OutName);Rewrite(OutFile);If ID=cImpossible ThenWriteLn(OutFile,'Impossible')Else If ID=cCannotDetermine ThenWriteLn(OutFile,'Cannot Determine')Else WriteLn(OutFile,Name[ID]);Close(OutFile);Halt;End;Procedure SetGuilty(CurID,NextID,NewValue:Integer); BeginIf Guilty[CurID,NextID]=0 ThenGuilty[CurID,NextID]:=NewValueElse If Guilty[CurID,NextID]<>NewValue ThenPrint(cImpossible);End;Procedure ReadStatement;Vari,j,CurID,NextID:Integer;CurStr,CurName:String;BeginFor i:=1 To P Do BeginReadLn(InFile,CurStr);CurStr:=CurStr+' #';CurName:=Copy(CurStr,1,Pos(':',CurStr)-1); CurStr:=Copy(CurStr,Pos(':',CurStr)+2,255); CurID:=0;For j:=1 To M DoIf CurName=Name[j] Then BeginCurID:=j;Break;End;If CurID=0 Then Continue;If CurStr='I am guilty. #' ThenSetGuilty(CurID,CurID,1)Else If CurStr='I am not guilty. #' ThenSetGuilty(CurID,CurID,-1)Else BeginCurName:=Copy(CurStr,1,Pos(' ',CurStr)-1); CurStr:=Copy(CurStr,Pos(' ',CurStr)+1,255); If CurName='Today' Then BeginFor j:=1 To 7 DoIf CurStr=DayState[j] Then BeginWhatDay[CurID,j]:=True;Break;End;EndElse BeginNextID:=0;For j:=1 To M DoIf CurName=Name[j] Then BeginNextID:=j;Break;End;If NextID=0 Then Continue;If CurStr='is guilty. #' ThenSetGuilty(CurID,NextID,1)Else If CurStr='is not guilty. #' Then SetGuilty(CurID,NextID,-1);End;End;End;End;Function Check(CurGuilty,CurDay:Integer):Boolean;VarSayT,SayF:Array[1..MM] Of Boolean;i,j,TCount,FCount:Integer;BeginFillChar(SayT,SizeOf(SayT),False);FillChar(SayF,SizeOf(SayF),False);For i:=1 To M Do BeginIf Guilty[i,CurGuilty]=1 ThenSayT[i]:=TrueElse If Guilty[i,CurGuilty]=-1 Then SayF[i]:=True;End;For i:=1 To M DoFor j:=1 To M DoIf j<>CurGuilty Then BeginIf Guilty[i,j]=1 ThenSayF[i]:=TrueElse If Guilty[i,j]=-1 ThenSayT[i]:=True;End;For i:=1 To M DoIf WhatDay[i,CurDay] Then SayT[i]:=True; For i:=1 To M DoFor j:=1 To 7 DoIf j<>CurDay ThenIf WhatDay[i,j] Then SayF[i]:=True; For i:=1 To M DoIf SayT[i] And SayF[i] Then BeginCheck:=False;Exit;End;TCount:=0; FCount:=0;For i:=1 To M Do BeginIf SayT[i] Then Inc(TCount);If SayF[i] Then Inc(FCount);End;If (FCount>N) Or (M-TCount<N) Then Begin Check:=False;Exit;End;Check:=True;End;BeginAssign(InFile,InName);Reset(InFile);ReadLn(InFile,M,N,P);For i:=1 To M Do ReadLn(InFile,Name[i]);FillChar(Guilty,SizeOf(Guilty),0);FillChar(WhatDay,SizeOf(WhatDay),False);ReadStatement;Close(InFile);FillChar(IsGuilty,SizeOf(IsGuilty),False);For i:=1 To M DoFor j:=1 To 7 DoIsGuilty[i]:=IsGuilty[i] Or Check(i,j);AnsC:=0;For i:=1 To M DoIf IsGuilty[i] Then BeginInc(AnsC);Ans:=i;End;If AnsC=0 ThenPrint(cImpossible)Else If AnsC>1 ThenPrint(cCannotDetermine)Else Print(Ans);End.第三题:加分二叉树【试题分析】一、题意分析1、任务描述:在中序遍历为(1,2,3,…,n)的各种二叉树中,选出加分最高的一棵二叉树,输出最高加分和对此二叉树的前序遍历。

相关主题