双连通分量缩点 并查集 竟然是第一次打
缩点后是一棵树
结论是(叶子节点+1)>>1
也就是每次取lca最浅的两个叶子连边
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline int read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; else if (c==EOF) return 0;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; return 1;
}
const int N=5005;
const int M=10005;
struct edge{
int u,v,next;
}G[M<<1];
int head[N],inum=1;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int fat[N];
inline void init(int n){
for (int i=1;i<=n;i++) fat[i]=i;
}
inline int Fat(int u){
return u==fat[u]?u:fat[u]=Fat(fat[u]);
}
int n,m;
int father[N],vst[N];
#define V G[p].v
inline void dfs(int u,int fa){
vst[u]=1;
for (int p=head[u];p;p=G[p].next)
if (p!=(fa^1)){
if (!vst[V])
father[V]=u,dfs(V,p);
else{
int tem=u,last=Fat(V),cur;
while ((cur=Fat(tem))!=last){
fat[cur]=Fat(father[cur]);
tem=Fat(father[cur]);
}
}
}
}
int deg[N],ans;
int main(){
int iu,iv;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
while (read(n) && read(m)){
init(n);
for (int i=1;i<=m;i++)
read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
dfs(1,0);
ans=0;
for (int i=1;i<=n;i++)
for (int p=head[i];p;p=G[p].next)
if (Fat(i)!=Fat(V))
deg[Fat(i)]++;
for (int i=1;i<=n;i++)
if (deg[i]==1)
ans++;
ans=(ans+1)>>1;
printf("%d\n",ans);
cl(head); inum=1; cl(vst); cl(father);
}
return 0;
}
还有不是我写的神奇的scc写法
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#include <queue>
#define MEM(a,x) memset(a,x,sizeof a)
#define eps 1e-8
#define MOD 10009
#define INF 99999999
#define ll __int64
#define bug cout<<"here"<<endl
#define fread freopen("ceshi.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)
using namespace std;
void read(int &x)
{
char ch;
x=0;
while(ch=getchar(),ch!=' '&&ch!='\n')
{
x=x*10+ch-'0';
}
}
const int MAXN=5010;
const int MAXM=10010;
struct Edge
{
int to,next;
}edge[2*MAXM];
int head[MAXN],tot;
int low[MAXN],dfn[MAXN],stack[MAXN],belong[MAXN];//belong数组的值是1~scc
int index,top;
int scc; //强连通分量的个数
bool instack[MAXN];
int num[MAXN];//各个强连通分量包含点个数 数组编号1~scc
//num数组不一定需要 结合实际情况
int degree[MAXN];
void addedge(int u,int v)
{
edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++;
}
void Tarjan(int u,int fa)
{
low[u]=dfn[u]=++index;
stack[++top]=u;
instack[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(i==(fa^1)) continue;
if(!dfn[v])
{
Tarjan(v,i);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
scc++;
while(1)
{
int v=stack[top--];
instack[v]=0;
belong[v]=scc;
if(v==u)
break;
}
}
}
int main()
{
// fread;
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
tot=index=top=scc=0;
MEM(head,-1);
MEM(low,0);
MEM(dfn,0);
MEM(instack,0);
MEM(degree,0);
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
Tarjan(1,-1);
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=edge[j].next)
{
int v=edge[j].to;
if(belong[i]!=belong[v])
degree[belong[i]]++;
}
}
int sum=0;
for(int i=1;i<=n;i++)
if(degree[i]==1)
sum++;
int ans=(sum+1)/2;
printf("%d\n",ans);
}
return 0;
}