题意:已知无向图,问添加最少的边使之成为边双连通图
思路:显然先缩点成一棵树,添加最少边使一棵树的边双连通
此处有结论:对于一棵树添加(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; }