poj-3177(无向图缩点)
题意:给你n个点,m条边的无向联通图,问你最少增加几条边,使得这个图每对点至少有两条路径
解题思路:考虑每个环内的点必定有>=2条路径,所以先把这个无向图中的环去掉,用并查集缩环,然后剩下的图一定是个割边树,只需要把度为1的结点数/2就是答案了(把这棵树变成环);
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int maxn=100500; struct Edge { int next;int to;int id; }edge[maxn]; int head[maxn],cnt,low[maxn],visit[maxn],dfn[maxn],step,ans,n,m; int f[maxn],x[maxn],y[maxn]; int deg[maxn]; void init() { memset(deg,0,sizeof(deg)); memset(head,-1,sizeof(head)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); for(int i=1;i<=n;i++) f[i]=i; cnt=step=0; } int findf(int u) { if(f[u]==u) return u; else { f[u]=findf(f[u]); return f[u]; } } void join(int u,int v) { int t1=findf(u);int t2=findf(v); if(t2!=t1) { f[t2]=t1; } } void add(int u,int v,int id) { edge[cnt].next=head[u];edge[cnt].to=v;edge[cnt].id=id;head[u]=cnt++; edge[cnt].next=head[v];edge[cnt].to=u;edge[cnt].id=id;head[v]=cnt++; } void tarjan(int u,int fa) { dfn[u]=low[u]=++step; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; int id=edge[i].id; if(fa==id) continue; if(!dfn[v]) { tarjan(v,id); low[u]=min(low[u],low[v]); if(dfn[u]<low[v]) { ans++; } else { join(u,v); } } else { low[u]=min(low[u],dfn[v]); } } } int main() { scanf("%d%d",&n,&m);init(); for(int i=1;i<=m;i++) { scanf("%d%d",&x[i],&y[i]); add(x[i],y[i],i); } tarjan(1,0); for(int i=1;i<=m;i++) { if(findf(x[i])==findf(y[i])) continue; else { deg[findf(x[i])]++;deg[findf(y[i])]++; } } int cot=0; for(int i=1;i<=n;i++) { if(deg[i]==1) cot++; } printf("%d\n",(cot+1)/2); }