题意:已知无向图,问添加最少的边使之成为边双连通图
思路:显然先缩点成一棵树,添加最少边使一棵树的边双连通
此处有结论:对于一棵树添加(1+leaf)>>1 条无向边就能构造成一个双连通图,构造方法显然(脑补一下
//216K 63MS C++ 1754B
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
struct node
{
int v,next;
}es[N*N];
int head[N];
int n,m;
int low[N],dfn[N],index;
int indeg[N];
void ini()
{
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
index=0;
memset(indeg,0,sizeof(indeg));
}
void tarjan(int u,int pa)
{
dfn[u]=low[u]=++index;
for(int i=head[u];~i;i=es[i].next)
{
int v=es[i].v;
if(dfn[v]==0)
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
if(v!=pa) low[u]=min(low[u],low[v]);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
ini();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
es[i].v=v;
es[i].next=head[u];
head[u]=i;
es[i+m].v=u;
es[i+m].next=head[v];
head[v]=i+m;
}
for(int i=1;i<=n;i++) if(dfn[i]==0) tarjan(i,-1);
for(int u=1;u<=n;u++)
{
for(int i=head[u];~i;i=es[i].next)
{
int v= es[i].v;
if(low[v]==low[u]) continue;
indeg[low[u]]++;
}
}
int leaf=0;
for(int i=1;i<=n;i++)
if(indeg[i]==1) leaf++;
printf("%d\n",(leaf+1)/2);
}
return 0;
}
上面这个代码是自己改编的一个tarjan,只有在这题中能用,还没证明出明确的错误,下面的是正解:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstring>
using namespace std;
int n,m;
const int N = 1000+100;
const int M = 2*N;
int head[N],cnt;
struct Edge
{
int v,nxt;
}es[M];
inline void add_edge(int u,int v)
{
es[cnt].v=v;
es[cnt].nxt=head[u];
head[u]=cnt++;
es[cnt].v=u;
es[cnt].nxt=head[v];
head[v]=cnt++;
}
typedef pair<int,int>pii;
pii bridge[M];
int dfn[N],sta[N],top,scc,index,col[N],low[N],cbr;
void tarjan(int u,int pa)
{
dfn[u]=low[u]=++index;
sta[++top]=u;
for(int i=head[u];~i;i=es[i].nxt)
{
int v=es[i].v;
if(v==pa) continue;
if(dfn[v]==0)
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])
{
scc++;
int vv;
do
{
vv=sta[top--];
col[vv]=scc;
}while(vv!=v);
bridge[++cbr]=pii(u,v);
}
}
else low[u]=min(low[u],dfn[v]);
}
}
int in[N];
void ini()
{
memset(dfn,0,sizeof(dfn));
memset(col,0,sizeof(col));
memset(in,0,sizeof(in));
memset(head,-1,sizeof(head));
top=scc=cbr=index=cnt=0;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
ini();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1);
if(top) scc++;
while(top)
{
col[sta[top--]]=scc;
}
for(int i=1;i<=cbr;i++)
{
int u=bridge[i].first,v=bridge[i].second;
in[col[u]]++;
in[col[v]]++;
}
int leaf=0;
for(int i=1;i<=scc;i++) if(in[i]==1)leaf++;
printf("%d\n",(leaf+1)>>1);
}
return 0;
}