当前位置:   article > 正文

2023首届大学生算法大赛 - 村庄

算法大赛

 


读题可以发现,如果两个村庄不能互相连通,那就算作一对 (a<b)。

显然是可以用floyd全局多源最短路来做的,如果不存在最短路,那么就是不能互通,但是这道题的数据范围N<=10^5,跑floyd复杂度为O(n^3)即10^15远大于10^8,显然是不行,复杂度级别只能是O(n),线性的,或者O(nlogn)。

看一下样例说明

显然如果两个村庄位于同一个连通块中,必然找不出(a<b),如果不在同一个连通块中,必然会产生(a<b),且数量刚好是第一个连通块的村庄数量 乘以 第二个连通块的数量。

为什么?

假设下图,1和2相连,3和4相连。

 明显可以发现1与3,4,都不相连,产生了第二个连通块村庄数量的(a<b)

2与3,4,也不相连,即为2*2=4。

所以直接使用并查集【模板】并查集 - 洛谷

初始给每个村庄都分配一个连通块,如果有桥相连,就把它们加入同一个连通块。

因为会摧毁编号为1~k的桥,所以输入的时候只需要i>k的部分,不需要合并被摧毁的部分。

 

细节(以样例说明):第四座桥把4接到了连通块1上,第五座桥把1接到了连通块3上,这里就出现了一个问题,4并没有被更新,所以最后还要再跑一遍find,更新所有情况。(本蒟蒻考试的时候熬夜昏迷了,没想到这一点)

应该能AC的代码

  1. #include <bits/stdc++.h>
  2. #define int long long
  3. using namespace std;
  4. int n,m,k,u,v,f[100001],cnt,ans;
  5. bitset<100001>vis;
  6. int a[100001];//连通块编号,其中村庄数量
  7. vector<int>a_;
  8. //定义f[i]=j为:i村庄在连通块j中
  9. int find(int x){
  10. if(f[x]==x)return x;
  11. else return f[x]= find(f[x]);
  12. }
  13. void unit(int x,int y){
  14. x= find(x),y= find(y);
  15. f[x]=y;
  16. }
  17. signed main(){
  18. ios::sync_with_stdio(false);
  19. cin.tie(nullptr),cout.tie(nullptr);
  20. cin>>n>>m>>k;
  21. for(int i=1;i<=n;++i)//初始化每个村庄的连通块
  22. f[i]=i;
  23. for(int i=1;i<=m;++i){
  24. cin>>u>>v;
  25. if(i>k){//1~k的桥全部被摧毁,只需要i>k的桥
  26. unit(u,v);
  27. }
  28. }
  29. for(int i=1;i<=n;++i)//跑一遍find,更新最终情况
  30. find(i);
  31. for(int i=1;i<=n;++i){//累计连通块编号
  32. a[f[i]]++;
  33. }
  34. for(int i=1;i<=n;++i)//把累计完的连通块全部拿出来
  35. if(a[i])a_.push_back(a[i]);
  36. for(int i=0;i<a_.size();++i)//配对连通块,累计答案
  37. for(int j=i+1;j<a_.size();++j)
  38. ans+=a_[i]*a_[j];
  39. cout<<ans;
  40. return 0;
  41. }

如果有错误或者有更好的思路,欢迎评论!

看看算法大赛还会不会开放OJ让我们再次测试。

同时预祝各位在2023/4/8的蓝桥杯省赛中while(true)rp++

别熬夜 : )

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/728712
推荐阅读
相关标签
  

闽ICP备14008679号