zoukankan      html  css  js  c++  java
  • 牛客练习赛32-D-MST+tarjin割边

    链接:https://ac.nowcoder.com/acm/contest/272/D
    来源:牛客网

    题目描述

    小p和他的朋友约定好去游乐场游玩,但是他们到了游乐场后却互相找不到对方了。
    游乐场可以看做是一张n个点,m条道路的图,每条道路有边权wi,表示第一次经过该道路时的花费(第二次及以后经过时花费为0)。
    现在,小p要去找他的朋友,但他的朋友行踪很诡异,小p总是要遍历完这n个点才能找到他,同时小p希望总花费最小。
    找到朋友的方案可能不唯一(具体看样例解释),小p想知道在这所有的方案中,有多少条边在每个方案中都会被经过。

    输入描述:

    第一行两个整数n, m. p,分别表示点数,边数,小p的初始位置。
    接下来m行,每行两个整数u, v, w表示从u到v有一条无向边,边权为w。

    输出描述:

    输出一个整数k,表示必须经过的边的数量。

        

    连通图没怎么学过很伤= =
      看了很久这个题解大概明白了思路,按照kruskal的方法,按照相同的w分类来讨论哪些边是必不可少的,如果在当前的图中e是割边,
    就说明付出w的代价使得图的连通性增强了1,显然这条边必不可少。如果不是割边,无论他会不会使得连通性增加我们都不必考虑。
      譬如w1<w2<w3在进行w2轮次时,如果两个端点已经联通这条边显然没必要,如果未联通且是割边,那他就是必不可少的边。因为按照
    贪心的思想必须这么做。
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=200050;
     4 int root,sum=1,dfn[maxn],low[maxn],ans[maxn],f[maxn];
     5 int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
     6 struct Ed{
     7     int u,v,w;
     8     bool operator<(const Ed &A)const{
     9         return w<A.w;
    10 }
    11 }E[maxn];
    12 struct Edge{int v,id,next;}e[maxn*2];
    13 int first[maxn],tot;
    14 void add(int u,int v,int id){
    15     e[tot].v=v;
    16     e[tot].id=id;
    17     e[tot].next=first[u];
    18     first[u]=tot++;
    19 }
    20 void tarjin(int u,int last){
    21     dfn[u]=low[u]=sum++;
    22     for(int i=first[u];~i;i=e[i].next){
    23         int v=e[i].v;
    24         if(i==(1^last))continue;
    25         if(dfn[v]){
    26             low[u]=min(low[u],dfn[v]);
    27         }
    28         else{
    29             tarjin(v,i);
    30             low[u]=min(low[u],low[v]);
    31             if(low[v]>dfn[u])ans[e[i].id]=1;
    32         }
    33     }
    34 }
    35 int main(){
    36     int i,j,n,m,p,u,v,w;
    37     scanf("%d%d%*d",&n,&m);
    38     tot=0;
    39     memset(first,-1,sizeof(first));
    40     for(i=1;i<=n;++i)f[i]=i; 
    41     for(i=0;i<m;++i){
    42         scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
    43     }
    44     sort(E,E+m);
    45     for(i=0;i<m;++i){
    46         j=i;
    47         while(j+1<m&&E[j+1].w==E[i].w)j++;
    48         tot=0;
    49         for(int k=i;k<=j;++k){
    50             int fu=getf(E[k].u),fv=getf(E[k].v);
    51             if(fu!=fv){
    52                 add(fu,fv,k);
    53                 add(fv,fu,k);
    54             }
    55         }
    56         for(int k=i;k<=j;++k){
    57             int fu=getf(E[k].u),fv=getf(E[k].v);
    58             if(fu==fv || dfn[fu]) continue;
    59             tarjin(fu,-1);
    60         }
    61         for(int k=i;k<=j;++k){
    62             int fu=getf(E[k].u),fv=getf(E[k].v);
    63             if(fu==fv)continue;
    64             first[fu]=first[fv]=-1;
    65             dfn[fu]=dfn[fv]=0;
    66             f[fu]=fv;
    67         }
    68         i=j;
    69     }
    70     int h=0;
    71     for(i=0;i<m;++i)h+=ans[i];
    72     cout<<h<<endl;
    73     return 0;
    74 }
    
    
    
     
  • 相关阅读:
    c#可以做什么
    C#是否快被年代所筛选?
    在.NET程序中,C#办法可用来封装代码
    关于程序员的小故事
    码农需了解的代码编写标准
    关于HTML代码的技巧
    分析一波编程语言的前景
    彻底解决Linux索引节点(inode)占用率高的告警
    Python29之字符str与字节bytes
    Python28之文件1
  • 原文地址:https://www.cnblogs.com/zzqc/p/10065033.html
Copyright © 2011-2022 走看看