Redundant Paths (side double connected components shrink point + thinking structure)

https://www.luogu.com.cn/problem/P2860


Idea: Two paths are separated from each other, which means that there is no overlap between the two paths.

That is to say, if one of the ways reached between any two points has to be reached 100%. So what is this one?

Think of the concept of a bridge in an undirected graph, which means that if this bridge is removed, the entire graph will not be connected.

It can be concluded that as long as there is no bridge in this graph, there must be two separate paths.

Therefore, this problem can be understood as finding the minimum number of edges required to convert a given undirected graph into an undirected graph without bridges.

Then consider shrinking points.

Undirected image reduction has been working for a long time. I saw that other people used bfs to do it, but I didn't do it right. It may be due to some characteristics of the forward star or I have a bug again. But this contraction point can be the same as the code for contracting the strongly connected components of the directed graph tarjan.

Because tarjan in the undirected graph just doesn't visit the father, and there is a different parameter in the updated timestamp in the nodes that have been visited. Then the other components are consistent with the strongly connected components, which means that the judgment conditions of dfn and low in a connected component are the same. That is, dfn[x]==low[x]. The rest is popped from the stack.

Specifically, you can see the shrinking point of the strong connected components in the previous tarjan plate.

However, there is a special place in the reduced point of the directed graph. When the two connected pieces are counted, they will be counted once in A->B, and B->A will be counted once. Therefore, when the degree of judgment is 1, it needs to be degree/2==1;

Finally, after shrinking the point, it is a tree, and the structure is found to be (number of leaf nodes+1)/2;

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<stack>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
vector<LL>g[maxn];
stack<LL>s;
LL n,m;
LL low[maxn],dfn[maxn],col[maxn],times=0,cnt=0,du[maxn],fa[maxn];
bool inq[maxn],ma[5010][5010];
void tarjan2(LL u)
{
    dfn[u]=low[u]=++times;
    s.push(u);inq[u]=true;
    for(LL i=0;i<g[u].size();i++){
        LL to=g[u][i];
        if(!dfn[to]){
            fa[to]=u;
            tarjan2(to);
            if(low[to]>dfn[u])
            {
                  ///  cout<<u<<" "<<to<<endl;
            }
            low[u]=min(low[u],low[to]);
        }
        else if(to!=fa[u])low[u]=min(low[u],dfn[to]);
    }
    if(low[u]==dfn[u])
    {
        cnt++;
        LL y;
        do{
           y=s.top();
           inq[y]=false;
           col[y]=cnt;
           s.pop();
        }while(y!=u);
        return;
    }
}

int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  cin>>n>>m;
  memset(fa,-1,sizeof(fa));
  for(LL i=1;i<=m;i++)
  {
     LL u,v;cin>>u>>v;
     if(ma[u][v]) continue;
     ma[u][v]=ma[v][u]=true;
     g[u].push_back(v);g[v].push_back(u);

  }
  for(LL i=1;i<=n;i++){

    if(!dfn[i]) tarjan2(i);
  }

  for(LL i=1;i<=n;i++){
    for(LL j=0;j<g[i].size();j++)
    {
        if(col[i]!=col[g[i][j]]) du[col[i]]++;
    }
  }

  LL sum=0;
  for(LL i=1;i<=cnt;i++){
   /// cout<<du[i]<<endl;
    if(du[i]==1) sum++;
  }
  cout<<(sum+1)/2<<endl;
  return 0;
}

 

Guess you like

Origin blog.csdn.net/zstuyyyyccccbbbb/article/details/108904709