当前位置:   article > 正文

Codeforces 160D Edges in MST(最小生成树+tarjan)_codeforces tarjan

codeforces tarjan

题目链接:Edges in MST

题意:给定n(1<=n<=1e5)个点,m(n-1=<m<=min(1e5,\frac{n*(n+1)}{2}))条边,判断每条边是否存在所有最小生成树(MST)中,或存在至少一颗中,或不存在任何最小生成树中

题解:判断是否存在最小生成树中可以将边权从小到大排序,按照正常求最小生成树的方式,从小到大枚举边,不过这里把边权相同的边放一起处理,对于每个边如果连的两个点已经在一个块中,说明这条边就一定不存在任何MST(最小生成树)中,因为在之前有更小的边已经能替代当前边,否则当前边一定至少存在一颗最小生成树中,而存在所有MST中的边,我们可以发现这些边一定是桥(唯一联通两个块的边)对于当前枚举的边权,把每个块当成一个点(用当前并查集父亲代表点),当前权值中边如果能联通两个不同块就建边,然后利用tarjan求dfn和low,我们可以通过low和dfn判断(low[son]>dfn[now]那么说明该儿子怎么都走不回来,说明该边是唯一能走向儿子的边即桥)哪些边是桥,当然,要注意建的是双向边,所以tarjan中要注意不能往回走

不懂可以看代码和注释

  1. #include<iostream>
  2. #include<stack>
  3. #include<list>
  4. #include<set>
  5. #include<vector>
  6. #include<algorithm>
  7. #include<math.h>
  8. #include<numeric>
  9. #include<map>
  10. #include<cstring>
  11. #include<queue>
  12. #include<iomanip>
  13. #include<cmath>
  14. #include<queue>
  15. #include <bitset>
  16. #include<unordered_map>
  17. #ifndef local
  18. #define endl '\n'
  19. #endif */
  20. #define mkp make_pair
  21. using namespace std;
  22. using std::bitset;
  23. typedef long long ll;
  24. typedef long double ld;
  25. const int inf=0x3f3f3f3f;
  26. const ll MAXN=2e6+10;
  27. const ll N=1e5+100;
  28. const ll mod=1e9+7;
  29. const ll hash_p1=1610612741;
  30. const ll hash_p2=805306457;
  31. const ll hash_p3=402653189;
  32. //-----------------------------------------------------------------------------------------------------------------*/
  33. // ll head[MAXN],net[MAXN],to[MAXN],edge[MAXN]/*流量*/,cost[MAXN]//费用;
  34. /*
  35. void add(ll u,ll v,ll w,ll s){
  36. to[++cnt]=v;net[cnt]=head[u];edge[cnt]=w;cost[cnt]=s;head[u]=cnt;
  37. to[++cnt]=u;net[cnt]=head[v];edge[cnt]=0;cost[cnt]=-s;head[v]=cnt;
  38. }
  39. struct elemt{
  40. int p,v;
  41. };
  42. struct comp{
  43. public:
  44. bool operator()(elemt v1,elemt v2){
  45. return v1.v<v2.v;
  46. }
  47. };
  48. -----------------------------------
  49. 求[1,MAXN]组合式和逆元
  50. ll mi(ll a,ll b){
  51. ll res=1;
  52. while(b){
  53. if(b%2){
  54. res=res*a%mod;
  55. }
  56. a=a*a%mod;
  57. }
  58. return res;
  59. }
  60. ll fac[MAXN],inv[MAXN]
  61. fac[0]=1;inv[0]=1;
  62. for(int i=1;i<=MAXN;i){
  63. fac[i]=(fac[i-1]*i)%mod;
  64. inv[i]=mi(fac[i],mod-2);
  65. }
  66. ll C(int m,int n){//组合式C(m,n);
  67. if(!n){
  68. return 1;
  69. }
  70. return fac[m]*(inv[n]*inv[m*-n]%mod)%mod;
  71. }
  72. ---------------------------------
  73. unordered_map<int,int>mp;
  74. //优先队列默认小顶堆 , greater<int> --小顶堆 less<int> --大顶堆
  75. priority_queue<elemt,vector<elemt>,comp>q;
  76. set<int>::iterator it=st.begin();
  77. */
  78. // vector<vector<int>>edge; 二维虚拟储存坐标
  79. //-----------------------------------------------------------------------------------------------------------------*/
  80. map<int,int>mp[N];
  81. int f[N];
  82. int find(int x){
  83. return f[x]==x?x:f[x]=find(f[x]);
  84. }
  85. void merge(int x,int y){
  86. int fx=find(x),fy=find(y);
  87. if(fx!=fy){
  88. f[fx]=fy;
  89. }
  90. }
  91. struct line{
  92. int u,v,w,p;
  93. };
  94. bool comp(line v1,line v2){
  95. return v1.w<v2.w;
  96. }
  97. line a[N];
  98. int ans[5*N];
  99. vector<pair<int,int>>edge[N];//存边
  100. int cnt=0;
  101. int low[N];//代表能到达的最早的点
  102. int dfn[N];//当前标号
  103. void tarjan(int x,int pre){//pre记录的是来的边的编号
  104. low[x]=dfn[x]=++cnt;
  105. for(int i=0;i<edge[x].size();i++){
  106. int to=edge[x][i].first,id=edge[x][i].second;
  107. if(!dfn[to]){
  108. tarjan(to,id);
  109. low[x]=min(low[x],low[to]);
  110. if(low[to]>dfn[x]){//已经回不来了,说明这是桥
  111. ans[a[id].p]=2;//更新答案
  112. }
  113. }
  114. else if(id!=pre){//和tarjan不同的是这里不能往回走,特判下
  115. low[x]=min(low[x],dfn[to]);
  116. }
  117. }
  118. }
  119. int main(){
  120. /*cout<<setiosflags(ios::fixed)<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(不含整数部分)*/
  121. /*cout<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(含整数部分)*/
  122. ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);//同步流
  123. int n,m;
  124. cin>>n>>m;
  125. for(int i=1;i<=n;i++){
  126. f[i]=i;
  127. }
  128. for(int i=1;i<=m;i++){
  129. cin>>a[i].u>>a[i].v>>a[i].w;
  130. a[i].p=i;
  131. }
  132. sort(a+1,a+m+1,comp);
  133. for(int i=1;i<=m;i++){
  134. int r=i+1;
  135. while(r<=m&&a[r].w==a[i].w){//确定当前w对应边界
  136. r++;
  137. }
  138. cnt=0;
  139. for(int j=i;j<r;j++){//清空
  140. int fx=find(a[j].u),fy=find(a[j].v);
  141. if(fx!=fy){
  142. edge[fx].clear();
  143. edge[fy].clear();
  144. low[fx]=dfn[fx]=0;
  145. low[fy]=dfn[fy]=0;
  146. }
  147. }
  148. for(int j=i;j<r;j++){//清空
  149. int fx=find(a[j].u),fy=find(a[j].v);
  150. if(fx!=fy){
  151. ans[a[j].p]=1;//标记为至少存在MST中
  152. edge[fx].push_back({fy,j});//建边
  153. edge[fy].push_back({fx,j});
  154. }
  155. }
  156. for(int j=i;j<r;j++){//跑tarjan
  157. int fx=find(a[j].u),fy=find(a[j].v);
  158. if(fx!=fy&&!dfn[fx]){
  159. tarjan(fx,0);
  160. }
  161. }
  162. for(int j=i;j<r;j++){
  163. merge(a[j].u,a[j].v);//合并边
  164. }
  165. i=r-1;//跳到下一个w值
  166. }
  167. for(int i=1;i<=m;i++){
  168. if(ans[i]==0){
  169. cout<<"none"<<endl;
  170. }
  171. else if(ans[i]==2){
  172. cout<<"any"<<endl;
  173. }
  174. else{
  175. cout<<"at least one"<<endl;
  176. }
  177. }
  178. return 0;
  179. }

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

闽ICP备14008679号