描述:
Peer-to-peer(P2P) 计算技术已经被广泛的应用到因特网数据交换。时下有很多P2P文件分享系统正在流行。
让我们看看一个P2P文件分享系统的简化模型:系统中有很多电脑,它们可以接受数据或将数据发送给别人。为了将问题简化,让我们假设在系统中只有一个大文件需要我们去关注。一些电脑已经拥有完整的文件(我们叫它“服务器”),一些则没有(我们叫它“客户端”)。客户端需要从服务器下载文件。当一个客户端得到了完整的文件,它就变成了一台服务器。
那些电脑不是一直在线。一个在线的客户端会从所有在线的服务器上下载文件。不同的服务器送给客户端不同部分的文件,因此客户端可以快速的下载文件。
现在给出每两台电脑间的传输速度,每台电脑在线及下线的时间以及哪些电脑在一开始就是服务器,请在一段时间内对系统的运行进行分析。
输入:
第一行包含一个整数表示测试数据的数量。
对于每组测试数据:
第1行:它包含两个正整数:n和T (n <= 20, T <= 1000) 意思是系统中有n台编号从1到n的电脑,你的任务是计算出系统开始运行的第T秒钟,每台电脑拥有文件的完整度(百分比)。
第2行:它包含两个正整数:k和S (k <= n, S <= 2^20) 意思是在系统开始运行时有k台服务器以及我们所关注的文件大小为S(KB)。
第3行:它包含K个整数,这是所有服务器的编号。
第4~n+3行:这n行形成一个n*n的矩阵。矩阵的第i行第j个数字表示i号电脑和j号电脑 (i 和 j 从1算起) 间的传输速度(单位 KB/s ,值不超过 2^10)。矩阵是对称的,对角线上的整数没有任何意义。
第n+4~2n+3行:每行包含一台电脑的上线/下线时刻表,格式如下(这些行按升序与电脑编号对应):
t online_time1 offline_time1 online_time2 offline_time2…online_timet offline_timet
t是一个不超过10的整数,时间全部都是非负的,并且呈升序。在online_timei和offtimei之间的这段时间内,电脑是在线的,并且能从其他电脑上下载数据或传输数据给其他电脑。
第2n+4行:它包含一个正整数m,表示系统中下载行为的数量。
第2n+5~2n+m+4:每行包含两个整数表示一个下载行为,格式如下:
download_timei computer_idi
从时刻download_timei开始,编号为computer_idi的电脑开始下载文件(0 <= download_timei <= T, 1 <= computer_idi <= n)。
这些行按时间非降序给出。保证服务器不会下载文件。保证在时刻download_timei编号为computer_idi的电脑在线(但有可能在发出一个下载命令后立即下线)。
当一个客户端开始下载,它会尝试连接所有的服务器同时从所有在线的服务器上下载数据。客户端的下载速度是所有连接的和。我们假设连接的建立是立即完成的,不花费时间,只有数据的传输会费时。
当一个客户端下线,未完成的下载任务会被保存,并在下次上线时继续。如果一个服务器上线,所有目前正在下载的电脑将会连接它并从中下载数据。更重要的是,当一个客户端变成一个服务器,它将立即开始向客户端传输数据。
注:为了简化问题,用来下载文件的时间应被向上取整(如果文件大小为 6KB 现在速度是 5KB/s,这个下载任务将会花费2秒钟而不是1.2秒钟 — 第一秒下载5KB,下一秒1KB)。
请注意,上述所有时间都以单位秒的形式给出。
输出:
对于每组测试数据,输出应包含n行,每行对应一台电脑。
第i行包含一个百分数,表示第i台电脑从系统开始运行直到T秒钟时所接收的数据的量。格式为‘percentage%’。这个百分数应该被向下取整。
提示:
有两台电脑。文件大小为1024KB,编号为1的电脑在开始时是服务器。当时间到达时刻10秒,编号为2的电脑开始从编号为1的电脑上下载文件直至其在时刻40秒时下线。总共下载了 10KB/s x 30s = 300KB。300/1024 29%。
思路:
按时间流动进行模拟。每过一秒就更新每台客户端的信息。唯一需要注意的是对时刻和时间的区分。
代码:
#include<iostream> #include<stdio.h> using namespace std; struct point //将每台电脑的信息用结构体封装起来。 { bool online[1000]; //在线时间,若第i秒内处于在线状态,则online[i]==true。 int sever_time; //该电脑成为服务器的时间。 int download_time; //开始下载的时刻。 int size; //拥有数据的大小。 }computer[20]; //电脑编号从0开始。 int n,T,k,S,speed[20][20]; //speed[i][j]表示电脑i与电脑j之间的传输速度。 void input() //输入 { scanf("%d%d%d%d",&n,&T,&k,&S); for(int i=0;i<k;i++) { int computer_id; scanf("%d",&computer_id); computer[computer_id-1].sever_time=0; //由于题目要求电脑编号从1开始,本程序定义电脑编号从0开始,所以编号应相应减1。 //若该电脑在系统开始运行时便是服务器,那它成为服务器的时刻便是0。 computer[computer_id-1].size=S; //拥有完整文件。 } for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&speed[i][j]); for(int i=0,t;i<n;i++) for(scanf("%d",&t);t>0;t--) { int online_time,offline_time; scanf("%d%d",&online_time,&offline_time); for(int j=online_time;j<offline_time;j++) computer[i].online[j]=true; } int m; for(scanf("%d",&m);m>0;m--) { int download_time,computer_id; scanf("%d%d",&download_time,&computer_id); computer[computer_id-1].download_time=download_time; } } void init() //初始化 { for(int i=0;i<20;i++) { for(int j=0;j<1000;j++) computer[i].online[j]=false; computer[i].sever_time=1000; computer[i].download_time=1000; computer[i].size=0; } } void solved() { for(int time=0;time<T;time++) //模拟时间流动。 for(int i=0;i<n;i++) //每秒中都遍历一次所有客户端。 if(time<computer[i].sever_time&&time>=computer[i].download_time&& computer[i].online[time]) //若该电脑为客户端且已经开始下载并在线。 for(int j=0;j<n;j++) //遍历所有服务器。 if(time>=computer[j].sever_time&&computer[j].online[time]) //若该电脑为服务器并在线。 { computer[i].size+=speed[i][j]; if(computer[i].size>=S) //若该客户端得到了完整的文件。 computer[i].sever_time=time+1; //规定其从下一秒开始成为服务器。 } } void output() //输出 { for(int i=0;i<n;i++) printf("%d%%\n",computer[i].size>=S?100:computer[i].size*100/S); } int main() { int t; for(scanf("%d",&t);t>0;t--) { init(); input(); solved(); output(); } }