原题
这是一道边双联通分量的板子题。
当我们对他缩点后,我们有一棵树,需要添加的边即为缩点后的(leaf+1)/2(把两个叶子连在一起一定是贪心最优解)
#include<cstdio>
#include<algorithm>
#define N 5010
#define M 10010
using namespace std;
int n,m,head[N],cnt=2,t,dfn[N],low[N],sum,from[N],in[N],bel[N],num;
bool is[2*M],vis[N];
struct hhh
{
int to,next;
}edge[2*M];
int read()
{
int ans=0,fu=1;
char j=getchar();
for (;(j<'0' || j>'9') && j!='-';j=getchar()) ;
if (j=='-') j=getchar(),fu=-1;
for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
return ans*fu;
}
void add(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void Tarjan(int x)
{
dfn[x]=low[x]=++t;
for (int i=head[x],v;i;i=edge[i].next)
{
v=edge[i].to;
if (i==(from[x]^1)) continue;
if (!dfn[v])
{
from[v]=i;
Tarjan(v);
low[x]=min(low[v],low[x]);
if (low[v]>dfn[x]) is[i]=is[i^1]=1,num++;
}
else low[x]=min(dfn[v],low[x]);
}
}
void dfs(int x)
{
vis[x]=1;
bel[x]=sum;
for (int i=head[x];i;i=edge[i].next)
{
if (is[i] || vis[edge[i].to]) continue;
dfs(edge[i].to);
}
}
int main()
{
n=read();
m=read();
for (int i=1,a,b;i<=m;i++)
{
a=read();
b=read();
add(a,b);
add(b,a);
}
Tarjan(1);
for (int i=1;i<=n;i++)
if (!bel[i]) sum++,dfs(i);
for (int i=2;i<=2*m+2;i++)
if (is[i]) in[bel[edge[i].to]]++;
t=0;
for (int i=1;i<=sum;i++)
if (in[i]==1) t++;
printf("%d",(t+1)/2);
return 0;
}