Gossiping --解题报告

本文解析了一道涉及多个变量的ACM竞赛题目,通过详细阐述题目的背景、输入输出要求及核心思路,提供了完整的解题过程。利用暴力搜索算法解决了司机间消息传递的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      下面是近期解决的ACM题目,差不多有一个月没连续上poj了。偶间有网友叫我帮他做ACM题目,于是又踏上ACM的征途。顺带把这题目提交到我的主战场poj的ACM.

 

 

题的出处:

(吉林ACM):http://acm.jlu.edu.cn/joj/showproblem.php?pid=1302

(北大ACM):http://acm.pku.edu.cn/JudgeOnline/problem?id=1370   

 

 

 

题目大意:

三个主要变量,n,d,s。n是线路的条数,d是司机的人数。s是站点的个数。

每个司机从一个站点出发,沿一条线路循环开着。在起点时每个司机都带有一个消息。当司机们在一个站点相遇时,他们互相告知其他人他所知道的消息。问给定一个状况,司机们是不是能够知道所有的消息 。

 

输入:

多case,每个case格式是:

n d s   //代表n条线路,d个司机,s个站点。输入0 0 0 结束。

//接下来,有2n行。分别对应第i个线路 ,及该线路上的司机 ,以该线路的哪个站点为起点 。

//第i个线路情况的输入

a1 a2 a3 ...//不定数,表示该线路的站点

si  di//不定组,表示第si个站点是第di个司机的起始点。

 

输出:

如果司机们能够知道所有人的消息,则输入"Yes",否则输出"No"

 

注意:

1.如果一名司机知道了甲司机的情况。则与乙相遇时,则自己所知道的所有消息都告诉乙(即是自己和甲的消息)

2.每条线路是循环开的。即是最后一个站点是与第一个站点相连的.

 

思路:

主要是用了暴力的搜索,因为数据量不大。过程中,遇到要解模方程的,鉴于数据量不大,用了一个遍历,减少了代码量。主要说明代码中有体现。这道关键是数据结构的,要组织好数据。

 

AC代码:

  1. #include<iostream>
  2. #include<cstdio>   //poj上要加上这句,不然会CE.
  3. using namespace std;
  4.  
  5. int n,m,k;// n是线路 ,m是司机人数 ,k是站的个数。
  6.  
  7. int path[20][30];//path[i]表示第i个路线经过的站点。
  8. int n_path[20];//表示第i条路线的站点个数。
  9. int visitor[30][2];//表示第i个司机在第[0]个起点,在[1]个条线上。
  10. int ans[1000];//辅助变量
  11. int visit[30][30];//表示i是不是得到j的消息 。
  12.  
  13.  
  14. void solve(int s,int t)
  15. {
  16. int i,j;
  17. int check;
  18. //检查i,j所在线上有没有相同的起点。check来标志
  19. int p=visitor[s][1];//s的所在线
  20. int q=visitor[t][1];//t的所在线。
  21. int starts=visitor[s][0];//s的起点
  22. int startt=visitor[t][0];//t的起点。
  23. if(p==q)
  24. {
  25. if(starts==startt)
  26. {
  27. check=1;
  28. }
  29. else return;
  30. }
  31. else
  32. {
  33. check=0;
  34. for(i=0;i<n_path[p];i++)
  35. {
  36. for(j=0;j<n_path[q];j++)
  37. {
  38. if(path[p][i]==path[q][j])
  39. {
  40. //说明两条线上有相同的站点。
  41. for(k=0;k<100;k++)
  42. {
  43. if((path[p][(starts+k)%n_path[p]]==path[p][i])
  44. &&(path[q][(startt+k)%n_path[q]]==path[p][i]))
  45. {
  46. check=1;
  47. break;
  48. }
  49. }
  50. if(check==1) break;
  51. }
  52. }
  53. if(check==1) break;
  54. }
  55. if(check==0) return ;
  56. }
  57. //说明两者相遇
  58. //p与q的所有消息 。
  59.  
  60.  
  61. visit[s][t]=1;
  62. for(j=1;j<=m;j++)
  63. {
  64. if(visit[s][j]==1||visit[j][s]==1)
  65. {
  66. visit[t][j]=visit[j][t]=1;
  67. }
  68. }
  69.  
  70. visit[t][s]=1;
  71. for(j=1;j<=m;j++)
  72. {
  73. if(visit[t][j]==1||visit[j][t]==1)
  74. {
  75. visit[s][j]=visit[j][s]=1;
  76. }
  77. }
  78. }
  79.  
  80.  
  81.  
  82. int main()
  83. {
  84. char str[100];
  85. int i,j,k;
  86. int num;
  87. int s;
  88. while(cin>>n>>m>>k)
  89. {
  90. if(n==0&&m==0&&k==0) break;
  91. getchar();
  92. //初始化
  93. for(i=1;i<=m;i++)
  94. {
  95. for(j=1;j<=m;j++)
  96. {
  97. if(i==j) visit[i][j]=1;
  98. else visit[i][j]=0;
  99. }
  100. }
  101. for(i=0;i<n;i++)
  102. {
  103. //输入站点 的。
  104. gets(str);
  105. n_path[i]=0;
  106. k=0;
  107. s=0;
  108. for(j=0;str[j]!='/0';j++)
  109. {
  110. if(str[j]==' ')
  111. {
  112. path[i][n_path[i]]=s;
  113. n_path[i]++;
  114. s=0;
  115. }
  116. else
  117. {
  118. s=str[j]-'0'+s*10;
  119. }
  120. }
  121. path[i][n_path[i]]=s;
  122. n_path[i]++;
  123. gets(str);
  124. num=0;
  125. s=0;
  126. for(j=0;str[j]!='/0';j++)
  127. {
  128. if(str[j]==' ')
  129. {
  130. ans[num++]=s;
  131. s=0;
  132. }
  133. else s=str[j]-'0'+s*10;
  134. }
  135. ans[num++]=s;
  136. for(j=0;j<num;j+=2)
  137. {
  138. for(k=0;k<n_path[i];k++)
  139. {
  140. if(ans[j]==path[i][k]) {ans[j]=k;break;}
  141. }
  142. visitor[ans[j+1]][0]=ans[j];
  143. visitor[ans[j+1]][1]=i;
  144. }
  145. }
  146. // for(i=1;i<=m;i++) cout<<visitor[i][0]<<" "<<visitor[i][1]<<endl;
  147.  
  148. /// 解决输入问题。下面解决问题。
  149. for(i=1;i<=m;i++)//看i能不能得到j的消息 。
  150. {
  151. for(j=i+1;j<=m;j++)
  152. {
  153. //判断i是不是能得到j的消息 。
  154. solve(i,j);
  155. }
  156. }
  157. int key=1;
  158. for(i=1;i<=m;i++)
  159. {
  160. for(j=1;j<=m;j++)
  161. {
  162. if(visit[i][j]==0) {key=0;break;}
  163. }
  164. if(key==0) break;
  165. }
  166. if(key) cout<<"Yes"<<endl;
  167. else cout<<"No"<<endl;
  168. }
  169. return 0;
  170. }
  171.  

 

<think>好的,用户之前询问了在OPNET中仿真Flooding协议的方法,现在又转向了Gossiping协议。我需要先明确Gossiping和Flooding的区别,以便提供针对性的指导。用户可能是在研究无线网络中的路由协议,或者是学生做相关项目,需要了解如何在仿真工具中实现不同的广播机制。 首先,Gossiping与Flooding的主要区别在于转发策略。Flooding是每个节点收到数据包后向所有邻居广播,而Gossiping则是随机选择一个邻居转发,这样可以减少网络流量但可能影响覆盖率和延迟。用户可能已经知道Flooding的缺点,比如广播风暴,想了解Gossiping如何优化。 接下来,用户的需求可能包括如何在OPNET中配置节点模型、进程模型以及统计量收集。需要对比之前的Flooding步骤,指出Gossiping的不同之处,比如随机选择转发节点、概率控制等。此外,用户可能需要了解如何设置转发概率和终止条件,避免无限传播。 还需要考虑用户的实际操作能力,是否需要详细代码示例,比如在进程模型中如何实现随机选择邻居。同时,用户可能对性能指标感兴趣,比如转发次数、覆盖率、能量消耗等,需要指导如何收集这些数据。 另外,需要注意OPNET的版本是否影响操作步骤,但可能用户使用的是较新的Riverbed版本,所以保持步骤通用。同时,提醒用户测试时的小规模网络和参数调整的重要性,比如概率值对结果的影响。 最后,用户可能遇到的问题包括覆盖率不足或转发效率低,需要提供排查建议,比如检查概率设置、邻居发现机制和终止条件是否正确。还可能涉及能量消耗的优化,这在无线传感器网络中尤为重要。 总结,回答需要结构清晰,分步骤说明如何在OPNET中实现Gossiping,重点突出与Flooding的不同点,提供代码示例和参数配置建议,并指导如何验证和优化仿真结果。</think>--- 在OPNET中仿真Gossiping(闲谈协议)需通过概率转发策略控制泛洪规模,以下是详细实现步骤: --- ### **1. Gossiping与Flooding的核心区别** - **转发机制** - Flooding:无条件广播给所有邻居 - Gossiping:以概率$p$随机选择一个邻居转发(或广播给部分邻居) - **优点**:减少冗余包,降低网络负载 - **缺点**:可能降低数据到达率(需通过概率$p$优化平衡) --- ### **2. 节点模型修改** - **网络层协议栈** 右键节点 → `Edit Attributes` → 网络层选择`<none>`(需自定义进程模型) - **添加邻居表** 在进程模型中维护动态邻居列表(通过HELLO包周期更新) ```c // 示例:HELLO包处理逻辑 case HELLO_PACKET_RECEIVED: { int neighbor_id = op_pk_nfd_get(pk, "sender_id"); update_neighbor_table(neighbor_id); // 添加或刷新邻居表项 op_pk_destroy(pk); break; } ``` --- ### **3. 进程模型关键逻辑** - **状态机扩展** 在Flooding状态机基础上增加概率判断分支(如`prob_forward`状态) ```c case OPC_INTRPT_STRM: { Packet* pk = op_pk_get(op_intrpt_strm()); if (!is_duplicate(pk)) { double rand_prob = op_dist_uniform(1.0); // 生成0~1随机数 if (rand_prob <= GOSSIP_PROB) // GOSSIP_PROB为预设转发概率 { int num_neighbors = get_neighbor_count(); if (num_neighbors > 0) { int selected = op_dist_uniform(1, num_neighbors); // 随机选一个邻居 op_pk_send(pk, selected); // 发送到指定接口 } else { op_pk_destroy(pk); } } else { op_pk_destroy(pk); // 丢弃包 } } break; } ``` --- ### **4. 参数配置优化** - **转发概率调节** 在进程模型头文件中定义宏`GOSSIP_PROB`(建议初始值0.6~0.8) ```c #define GOSSIP_PROB 0.7 // 70%概率转发 ``` - **邻居发现协议** 配置HELLO包间隔(如1秒),影响邻居表准确性 ```c #define HELLO_INTERVAL 1.0 // 单位:秒 ``` --- ### **5. 统计量设计** - **关键指标** - **网络层**:`Traffic Forwarded/Received`(对比Flooding的流量差异) - **自定义指标**: - 覆盖率:成功接收数据的节点比例 - 平均转发次数:单包全网转发次数 ```c // 统计覆盖率示例 if (is_destination(pk)) { coverage_count++; op_stat_write("Coverage Ratio", (double)coverage_count / total_nodes); } ``` --- ### **6. 防无限传播机制** - **TTL衰减** 在包头添加`ttl`字段,每次转发减1,归零则丢弃 ```c int ttl = op_pk_nfd_get(pk, "ttl"); if (ttl > 0) { op_pk_nfd_set(pk, "ttl", ttl-1); } else { op_pk_destroy(pk); return; } ``` - **序列号检测** 记录`(源节点ID, 序列号)`二元组,防止重复处理 --- ### **7. 典型问题排查** - **覆盖率不足** - 提高`GOSSIP_PROB` - 缩短HELLO包间隔(确保邻居表准确) - **端到端时延过高** - 降低MAC层重传次数(如修改`mac_retry_limit`) - 减少随机转发前的等待抖动 - **能量消耗不均衡** 在能耗统计中监控节点转发次数,引入负载均衡策略 --- ### **与Flooding仿真的对比实验** | **指标** | **Flooding** | **Gossiping** | |------------------|--------------------|---------------------------| | 网络负载 | 高($O(n^2)$) | 中(依赖$p$) | | 覆盖率 | 100%(理想情况) | 概率收敛(需调优$p$) | | 鲁棒性 | 高(冗余路径多) | 较低(依赖随机选择) | | 适用场景 | 小规模紧急广播 | 大规模节能网络 | --- ### **扩展:混合策略(Flooding+Gossiping)** 1. **初始阶段**:使用Flooding快速覆盖近邻 2. **扩散阶段**:切换为Gossiping控制远端传播 3. **实现方法**:在包头添加`phase`字段,进程模型根据阶段切换转发策略 --- 通过调整转发概率$p$和TTL初始值,可在OPNET中观察Gossiping协议在负载、时延、覆盖率之间的权衡关系。建议使用`op_anim_script`录制泛洪过程动画,直观验证协议行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值