14:
关键字 强联通
题目求最多加多少条边使图不不再是一个强联通
我们逆向思维:
先假设n*(n-1)边 那么一定强联通 ,问最少减去多少条边 不再联通
那么只要枚举一个联通块就可以
因为其他边肯定与他有联系
CODE:
#pragma comment(linker,"/STACK:102400000,102400000") #include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #include<math.h> #include<stack> using namespace std; const int N=200010; const int M=1000020; struct node { int v,next; }e[M*2]; int head[N]; int dfn[N],low[N],dp[N][2]; int vis[M]; int n,m,cnt,ans; void add(int u,int v) { e[cnt].v=v; e[cnt].next=head[u]; head[u]=cnt++; } void dfs(int u) { dfn[u]=low[u]=cnt++; dp[u][0]=dp[u][1]=0; for (int i=head[u];i!=-1;i=e[i].next) { int j=e[i].v; if (!vis[i>>1]) { vis[i>>1]=1; if (dfn[j]==0) { dfs(j); ans+=dfn[u]<low[j]; int tmp=dp[j][0]+(dfn[u]<low[j]); if (tmp>dp[u][0]){ dp[u][1]=dp[u][0],dp[u][0]=tmp;} else if (tmp>dp[u][1]) dp[u][1]=tmp; low[u]=min(low[u],low[j]); } else low[u]=min(low[u],dfn[j]); } } } int main() { while (scanf("%d%d",&n,&m)) { if (n==0&&m==0) break; cnt=ans=0; memset(head,-1,sizeof(head)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); while (m--) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } cnt=1; memset(vis,0,sizeof(vis)); dfs(1); int tmp=0; for (int i=1;i<=n;i++) tmp=max(tmp,dp[i][0]+dp[i][1]); printf("%d ",ans-tmp); } return 0; }