这个题应该是求双连通分量,但我一直却弄成了点连通分量,导致一直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;
}