这个题应该是求双连通分量,但我一直却弄成了点连通分量,导致一直WA。不过性质想到了,是求连通分量缩点,然后答案是度数为1的点加上度数为0的点的2倍然后再除以2
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<stack> #include<vector> using namespace std; const int maxn=1e3+100; const int maxm=1e6+100; int e,n,m,pnt[maxm],nxt[maxm],head[maxn]; int dfs_clock,dfn[maxn],low[maxn],cnt[maxn],bccno[maxn],grades[maxn],bccnt; bool iscut[maxn],isbridge[maxn][maxn]; struct Edge { int u; int v; Edge(){} Edge(int su,int sv) { u=su; v=sv; } }; stack<Edge> s; void AddEdge(int u,int v) { pnt[e]=v;nxt[e]=head[u];head[u]=e++; pnt[e]=u;nxt[e]=head[v];head[v]=e++; } int DFS(int u,int f) { dfn[u]=low[u]=++dfs_clock; int child=0; for(int i=head[u];i!=-1;i=nxt[i]) { if(!dfn[pnt[i]]) { s.push(Edge(u,pnt[i])); child++; low[u]=min(low[u],DFS(pnt[i],u)); if(low[pnt[i]]>=dfn[u]) { iscut[u]=true; isbridge[pnt[i]][u]=isbridge[u][pnt[i]]=1; } } else if(dfn[pnt[i]]<dfn[u]&&pnt[i]!=f) { s.push(Edge(u,pnt[i])); low[u]=min(low[u],dfn[pnt[i]]); } } if(f<0&&child==1) iscut[u]=0; return low[u]; } void dfs(int u) { for(int i=head[u];i!=-1;i=nxt[i]) if(!bccno[pnt[i]]&&!isbridge[u][pnt[i]]) { bccno[pnt[i]]=bccnt; dfs(pnt[i]); } } void Init() { e=dfs_clock=bccnt=0; memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(iscut,0,sizeof(iscut)); } void solve() { memset(bccno,0,sizeof(bccno)); memset(grades,0,sizeof(grades)); memset(isbridge,0,sizeof(isbridge)); for(int i=1;i<=n;i++) if(!dfn[i]) DFS(i,-1); for(int i=1;i<=n;i++) if(!bccno[i]) { bccnt++; bccno[i]=bccnt; dfs(i); } if(bccnt==1) { printf("0\n"); return; } for(int u=1;u<=n;u++) for(int i=head[u];i!=-1;i=nxt[i]) if(bccno[u]!=bccno[pnt[i]]) grades[bccno[pnt[i]]]++; int ans=0; for(int i=1;i<=bccnt;i++) { if(grades[i]==0) ans+=2; if(grades[i]==1) ans++; } printf("%d\n",(ans+1)>>1); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { Init(); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); AddEdge(u,v); } solve(); } return 0; }