大意:至少加几条边让图联通。
思路:让图联通的话肯定会与度数有关。所以找到入出度最大的补上即可。
#include<map> #include<queue> #include<cmath> #include<cstdio> #include<stack> #include<iostream> #include<cstring> #include<algorithm> #define LL int #define inf 0x3f3f3f3f #define eps 1e-8 #include<vector> #define ls l,mid,rt<<1 #define rs mid+1,r,rt<<1|1 using namespace std; const int nv = 21000; const int ne = 51000; struct node{ int to,next; }q[ne<<1]; int head[ne<<1],dfn[nv],num[nv],in[nv],stk[nv],low[nv]; int cnt,top,tim,scc,out[nv],n,mi; bool vis[nv]; void Add(int a,int b){ q[cnt].to = b; q[cnt].next = head[a]; head[a] = cnt++; } void Tarjan(int u){ dfn[u] = low[u] = tim++; stk[top++] = u; vis[u] = 1; for(int i = head[u];~i;i=q[i].next){ int v = q[i].to; if(!dfn[v]){ Tarjan(v); low[u] = min(low[u],low[v]); } else if(vis[v]){ low[u] = min(low[u],dfn[v]); } } if(dfn[u]== low[u]){ scc++; while(top>0&&stk[top] != u){ int now = stk[--top]; num[now] = scc; vis[now] = 0 ; } } } void init(){ scc = cnt = top = 0; tim = 1; memset(head,-1,sizeof(head)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,false,sizeof(vis)); memset(num,0,sizeof(num)); } int main(){ int n,m,i,j,k,cla,a,b; scanf("%d",&cla); while( cla-- ){ init(); scanf("%d%d",&n,&m); for(i = 0;i < m;++ i){ scanf("%d%d",&a,&b); Add(a,b); } for(i = 1;i <= n;++ i) if(!dfn[i]) Tarjan(i); if(scc==1){ puts("0");continue; } for(i = 1;i <= n;++ i){ for(j = head[i] ;~j;j = q[j].next){ int v = q[j].to; if(num[i]!=num[v]){ out[num[i]]++; in[num[v] ]++; } } } int s2 = 0,s1 = 0; for(i = 1;i <= scc;++ i ){ if(!in[i]) s1++; if(!out[i]) s2++; } printf("%d\n",max(s1,s2)); } return 0; }