NC16853. [NOI1998]SERNET模拟
描述
计算机网络是现代科技发展的热点,传输性能是计算机网络的主要性能指标。SERKOI网络开发小组设计了一种称为SERNET的网络,并希望开发一个模拟软件来模拟该网络的数据传输情况,进而计算出网络的传输性能。
SERNET网络由服务器及连接它们的网络传输线路组成,服务器用服务器地址予以标识,网络传输线路为双向传输线路。网络传输过程中将各种待传输数据分割为若干个大小相同的数据包,以数据包为单位进行传输。数据包在传输线路上传输时需要一定的传输时间,不同的传输线路的传输时间不同。服务器处理数据的时间较之于传输时间很小,可忽略不计。每一个数据包中除了包括具体的数据信息外,还含有如下标识信息:
数据包编号
数据包源服务器地址
数据包目的服务器地址
网络传输的功能就是将一个个数据包从源服务器传输到目的服务器。对于每一个数据包,具体的网络传输方案为:
源服务器将待发送的数据包一律复制若干份并向与之相连的所有服务器发送该数据包。服务器接收到一个数据包后,如果该数据包符合下面任何一个条件:
数据包的源服务器地址与本服务器地址相同
数据包的目的服务器地址与本服务器地址相同
本服务器已转发过与该数据包编号相同的数据包
则接收该数据包;否则,服务器将其复制若干份并向与它相连的所有服务器转发该数据包。这里,两台服务器“相连”的含义指它们之间有网络传输线路直接相连。
现在需要你编一个程序来模拟SERNET网络中的数据包传输情况。
输入描述
第一行为一个正整数N(N<100),表示SERNET中服务器的数目。第二行有N个互不相等的不超过100的正整数,表示每个服务器的地址。 第三行有一个正整数M,表示SERNET中传输线路的数目。接下来的M行每行用三个正整数表示一条传输线路连接的两台服务器的地址以及该传输线路的传输时间。线路传输时间为不超过100的正整数。 接下来的一行为一个正整数K(K<10000),表示SERNET中数据包的数目。以下的K行每行表示一个数据包的信息,格式为:
数据包编号 起始发送时间 源服务器地址 目的服务器地址
其中数据包编号为互不相同的小于100000的正整数。
输入文件的最后一行为一个正整数T(T<10000),T为输出时刻。
输入文件中同一行相邻两项之间用一个或多个空格隔开。
输出描述
输出文件的第一行为一个整数P,表示T时刻后还在网络中传输的数据包数目(编号相同的数据包为同一数据包)。
示例1
输入:
4 57 42 10 93 4 57 42 6 42 93 5 42 10 2 10 93 10 2 433 10 57 10 5678 11 42 93 23
输出:
1
Pascal(fpc 3.0.2) 解法, 执行用时: 6ms, 内存消耗: 256K, 提交时间: 2019-01-07 18:12:04
program NOI98_5; const MaxN = 99; {服务器数的上限} MaxK = 9999; {数据包数的上限} type TPackage = record {数据包类型} Send: Word; {发出时刻} Source: Byte; {源服务器} Target: Byte; {目的服务器} end; TLink = record {传输线的时间类型} Short: Byte; {最短传输时间} Long: Byte; {最长传输时间} end; var N: Byte; {服务器数} K: Word; {数据包数} T: Word; {输出时刻} P: Word; {输出时刻后还在网络中传输的数据包数} Index: array [1 .. MaxN] of Byte; {Index[I]——地址为I的服务器序号} Links: array [1 .. MaxN, 1.. MaxN] of TLink; {Links[I, J]——服务器I的服务器J的传输时间} Packages: array [1 .. 10000] of TPackage; procedure Init; {输入数据} var I, J: Word; M: Word; {传输线路数} S1, S2: Byte; {当前传输线相连的两个服务器序号} Time: Word; {当前传输线路的传输时间} PackageID: Longint; {数据包编号} Begin Reset(Input); Readln(N); {读服务器数} for I := 1 to N do begin {度入每个服务器地址,计算Index表} Read(J); Index[J] := I; end; Readln(M); {读传输线路输} FillChar(Links, Sizeof(Links), 0); {Links表初始化} for I := 1 to M do begin {输入每条线路的信息} Readln(S1, S2, Time); {读相连的两台服务器地址和传输时间} S1 := Index[S1]; {计算这两台服务器的序号} S2 := Index[S2]; if (Links[S1,S2].Short=0)or(Links[S1,S2].Short>Time) then {计算该线路的最短传输时间和最长传输时间} Links[S1, S2].Short := Time; if Links[S1, S2].Long < Time then Links[S1, S2].Long := Time; Links[S2, S1] := Links[S1, S2]; end; Readln(K); {读数据包数} for I := 1 to K do {读每一个数据包的信息} with Packages[I] do Readln(PackageID, Send, Source, Target); {读第I个数据包的编号,起始发送时间,源服务器地址,目的服务器地址} Readln(T); {读入输出时刻} Close(Input); end; function Alive(It: TPackage): Boolean; {模拟数据包It在T时刻还在网络中传输,则返回True;否则返回False} var I, J: Byte; Time: Word; Receive: array [1 .. MaxN] of Word; {Receive[I]:服务器I收到下一个数据的时刻} Accepted: array [1..MaxN] of Boolean; {Accepted[I]:为服务器I接收It的标志} begin Alive := True; FillChar(Receive, Sizeof(Receive), $FF); {初始时,所有服务器未收到任何数据包} FillChar(Accepted, Sizeof(Accepted), False); Receive[Index[It.Source]] := It.Send; {源服务器在发送了It后开始接受下一个数据包} if It.Source <> It.Target then Accepted[Index[It.Target]] := True; {若源服务器与目的服务器不同,则确定目的服务器收到数据包It} repeat I := 1; {计算最早收到下一个数据包的服务器I} for J := 2 to N do if Receive[J] < Receive[I] then I := J; if Receive[I] = $FFFF then Break; {若所有服务器收到It,则返回false} if not Accepted[I] then begin {若服务器未接收数据包It,则搜索与服务器I相连的服务器} for J := 1 to N do if Links[I, J].Short <> 0 then begin Time := Receive[I] + Links[I, J].Short; if Time < Receive[J] then Receive[J] := Time; {若服务器J能在Receive[J]前收到来自服务器I发来的数据包} if Receive[I] + Links[I, J].Long > T then Exit; {若在该线路上传输It将超是,则返回True} end; Accepted[I] := True; {设定服务器I收到It标志} end; Receive[I] := $FFFF; {设服务器I转发过It标志} until False; Alive := False; {It在TimeLine时刻前结束传输} end; procedure Main; {统计T时刻后还在网络中传输的数据包数} var Y: Word; begin P := 0; for Y := 1 to K do if Alive(Packages[Y]) then Inc(P); end; procedure Out; {输出} begin Rewrite(Output); Writeln(P); Close(Output); end; begin Init; Main; Out; end.
C++(clang++ 11.0.1) 解法, 执行用时: 20ms, 内存消耗: 460K, 提交时间: 2023-03-18 16:53:33
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> const int MAXN=101,MAXK=10001,INF=0x7FFFFFF; using namespace std; struct packet { int id,s,t,stime; }P[MAXK]; int N,M,K,S,T,dia,QuestTime,Ans; int mapping[MAXN],adjm[MAXN][MAXN],dist[MAXN][MAXN],farest[MAXN]; void init() { int i,j,a,b,v; scanf("%d",&N); for (i=1;i<=N;i++) { scanf("%d",&a); mapping[a]=i; for (j=1;j<=N;j++) adjm[i][j]=INF; adjm[i][i]=0; } scanf("%d",&M); for (i=1;i<=M;i++) { scanf("%d%d%d",&a,&b,&v); a=mapping[a];b=mapping[b]; if (v>farest[a]) farest[a]=v; if (v>farest[b]) farest[b]=v; adjm[a][b]=adjm[b][a]=v; } scanf("%d",&K); for (i=1;i<=K;i++) scanf("%d%d%d%d",&P[i].id,&P[i].stime,&P[i].s,&P[i].t); scanf("%d",&QuestTime); } void floyd() { int i,j,k; for (i=1;i<=N;i++) for (j=1;j<=N;j++) dist[i][j]=adjm[i][j]; for (k=1;k<=N;k++) { if (k==S || k==T) continue; for (i=1;i<=N;i++) { if (i==T) continue; for (j=1;j<=N;j++) { if (j==S) continue; if (dist[i][k]+dist[k][j]<dist[i][j]) dist[i][j]=dist[i][k]+dist[k][j]; } } } i=S; for (j=1;j<=N;j++) if (i!=j && i!=T && j!=S && dist[i][j]!=INF) { k=farest[j]; if (j==T) k=0; if (dist[i][j] + k>dia) dia=dist[i][j] + k; } } void solve() { for (int i=1;i<=K;i++) { S=mapping[P[i].s];T=mapping[P[i].t]; dia=0; floyd(); int last=dia+P[i].stime; if (last>QuestTime) Ans++; } } int main() { init(); solve(); printf("%d",Ans); return 0; }