HDU4612-强连通分量&树的直径-warmup

来源:互联网 发布:java获取 路径 编辑:程序博客网 时间:2024/05/21 07:04

给定一个图,要求你添加一个边,使这个图的桥最少。
我几乎是蒙蔽的。
先缩个点,然后求一遍树的直径。
然后用 原先的桥数 减去树的直径就好了。
或者 用强连通分量树 -1-树的直径
(缩点后一个scc就是一个点,而桥就是边,并且是树,如果不是树就缩点缩了)
这里写图片描述
发现了吧。有的人把剩下的桥 叫做 枝叶边, 就是那个红点那个边
就是要求的 剩下的最小的桥数
(要求添加的那个一边,从直径头到尾,把所有直径边想当桥的愿望都给否定了)

#include <iostream>#include <cstdio>#include <cstring>#include <bits/stdc++.h>/*先缩点,变成一个树,然后再求树的直径,然后那个原来的桥数减去直径  在减1(因为还要在添)*/using namespace std;const int maxm=1000008;const int maxn=200005;struct Node{  int to,next,cost;}node[maxm*2];int len;int head[maxn];void add(int u,int v){   node[len].to=v;   node[len].next=head[u];   //node[len].cost=w;   head[u]=len++;}int low[maxn];int dfn[maxn];int cnt[maxn];int num[maxn];int index;int bridge;int scc;vector<int>G[maxn];stack<int>s;int m,n,a,b;void init(){  index=0;  len=0;  scc=0;  bridge=0;  memset(head,-1,sizeof(head));//链表  memset(num,0,sizeof(num));//各scc多少个  memset(dfn,0,sizeof(dfn));//  memset(low,0,sizeof(low));  for(int i=0;i<maxn;i++)     G[i].clear();    while(!s.empty())         s.pop();}void tarjan(int m,int pre){     low[m]=dfn[m]=++index;     s.push(m);     for(int i=head[m];i!=-1;i=node[i].next)    {        if(i==(pre^1))continue;        int v=node[i].to;        if(!dfn[v])            {            tarjan(v,i);            if(low[v]<low[m])                low[m]=low[v];            if(low[v]>dfn[m])//这就是 桥的条件                bridge++;        }else if(dfn[v]<low[m])//下一个点的dfs顺序比他能到达的小,就换            low[m]=dfn[v];    }     if(low[m]==dfn[m])    {        scc++;        for(;;)        {            int x = s.top();s.pop();            cnt[x]=scc;            num[scc]++;            if(x==m)break;        }    }}int dis[maxn];bool vis[maxn];int dfs(int a){    for(int i=0;i<G[a].size();i++){        int v=G[a][i];        if(!vis[v])        {vis[v]=true;        dis[v]=dis[a]+1;        dfs(v);        }    }}void solve(){   memset(dis,0,sizeof(dis));   memset(vis,false,sizeof(vis));   vis[1]=true;   dis[1]=0;   dfs(1);   int dex=1;   int sum=-1;   for(int i=1;i<=scc;i++){      if(dis[i]>sum)        {sum=dis[i];//         dex=i;        }   }   memset(dis,0,sizeof(dis));   memset(vis,false,sizeof(vis));   vis[dex]=true;   dis[dex]=0;   dfs(dex);   sum=-1;   dex=1;   for(int i=1;i<=scc;i++){       if(dis[i]>sum)         sum=dis[i];   }  // cout<<bridge<<endl;   //cout<<sum<<endl;//printf("%d\n",bridge-sum);printf("%d\n",scc-1-sum);}int main(){   while(~scanf("%d%d",&m,&n)){        if(m==0||n==0) break;         init();         for(int i=1;i<=n;i++){            scanf("%d%d",&a,&b);            add(a,b);            add(b,a);         }         for(int i=1;i<=m;i++)             if(!dfn[i])            tarjan(i,-1);         for(int i=1;i<=m;i++){            for(int j=head[i];j!=-1;j=node[j].next)            {  int v=node[j].to;                if(cnt[v]==cnt[i]) continue;                G[cnt[v]].push_back(cnt[i]);                G[cnt[i]].push_back(cnt[v]);//缩点            }         }         solve();    }    return 0;}