http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2506
连通分量 缩点后形成新的图(不用新建也可以) 是一个森林
如果缩点后是就剩一个点 则答案为 0
否则 对于缩点后的某一个点 如果和它相连点(缩点后的)有大于等于2个 则无需再连
如果和它相连的有一个点 则需要加一个边连接它 如果没有点和它相连 则需要加两条
统计总共需要加的边的个数sum 因为每条边连接两个点 所以答案为 (sum+1)/2
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> #include<vector> #include<stack> #include<queue> #include<set> #include<algorithm> #define LL long long using namespace std; const int N=5015; const int M=10005; int head[N],I; struct node { int j,next; }side[M*2]; int dfn[N],low[N],f[N],deep; bool visited[N],in[N]; stack<int>st; set<int>numt[N]; void add(int i,int j) { side[I].j=j; side[I].next=head[i]; head[i]=I++; } void dfs(int x,int pre) { dfn[x]=low[x]=deep++; st.push(x); in[x]=true; visited[x]=true; for(int t=head[x];t!=-1;t=side[t].next) { int j=side[t].j; if(j==pre) continue; if(!visited[j]) { dfs(j,x); low[x]=min(low[x],low[j]); }else if(in[j]) { low[x]=min(low[x],dfn[j]); } } if(low[x]==dfn[x]) { while(st.top()!=x) { in[st.top()]=false; f[st.top()]=x; st.pop(); } in[st.top()]=false; f[st.top()]=x; st.pop(); } } int main() { //freopen("data.in","r",stdin); int T; scanf("%d",&T); while(T--) { memset(head,-1,sizeof(head)); I=0; int n,m; scanf("%d %d",&n,&m); while(m--) { int l,r; scanf("%d %d",&l,&r); add(l,r); add(r,l); } while(!st.empty()) st.pop(); memset(in,false,sizeof(in)); memset(visited ,false,sizeof(visited)); deep=1; int treenum=0; for(int i=1;i<=n;++i) { if(!visited[i]) { dfs(i,-1); ++treenum; } } for(int i=1;i<=n;++i) numt[i].clear(); for(int i=1;i<=n;++i) { for(int t=head[i];t!=-1;t=side[t].next) { int j=side[t].j; if(f[i]!=f[j]) { numt[f[i]].insert(f[j]); } } } int leftnum=0; int sum=0; for(int i=1;i<=n;++i) { if(f[i]==i) { if(numt[i].size()==0) {sum+=2;leftnum++;} if(numt[i].size()==1) {sum+=1;leftnum++;} } } if(treenum==1&&leftnum==1) { printf("0\n"); }else { printf("%d\n",(sum+1)/2); } } return 0; }