本题题意是 给你n个点m条边 要求如果需要将这个图变成强连通最少需要多少条边
我的做法是强连通分量缩点+求度 取 max(出度为0的数量,入度为0的数量)的值就是
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std;
#define MAXN 20010 vector <int> e[MAXN]; bool instack[MAXN]; int dfn[MAXN],low[MAXN],top,times; int stack[MAXN]; int n,m; int sum[MAXN]; int tran[MAXN]; int chu[MAXN]; int ru[MAXN]; void tarjan(int u){ dfn[u]=low[u]=++times; stack[top++]=u; instack[u]=true; for(int i=0;i<(int)e[u].size();i++){ int v=e[u][i]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],low[v]); }
if(dfn[u]==low[u]){ int tot=0; ++sum[0]; do{ u=stack[--top]; ++tot; instack[u]=false; tran[u]=sum[0]; }while(low[u]!=dfn[u]); sum[sum[0]]=tot; } } void init(){ for(int i=0;i<MAXN;i++)e[i].clear(); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(instack,0,sizeof(instack)); memset(sum,0,sizeof(sum)); memset(tran,0,sizeof(tran)); memset(chu,0,sizeof(chu)); memset(ru,0,sizeof(ru)); top=times=0; } int main() { int t; scanf("%d",&t); while(t--){ init(); scanf("%d%d",&n,&m); for(int i=0,x,y;i<m;i++){ scanf("%d%d",&x,&y); e[x].push_back(y); } if(n==1){ puts("0"); continue; } if(!m){ printf("%d\n",n); continue; } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); if(sum[0]==1){ puts("0"); continue; } for(int i=1;i<=n;i++){ for(int j=0;j<(int)e[i].size();j++){ int v=e[i][j]; if(tran[i]!=tran[v]){ chu[tran[i]]++; ru[tran[v]]++; } } } int cchu=0,rrru=0; for(int i=1;i<=sum[0];i++){ if(chu[i]==0)++cchu; if(ru[i]==0)++rrru; } printf("%d\n",max(cchu,rrru)); } return 0; }
|