贴一个网上讲tarjan的博客
https://blog.csdn.net/qq_34374664/article/details/77488976
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> #define maxn 105 #define maxm 1005 using namespace std; stack<int>st; int num,last[maxn],dfn[maxn],low[maxn],vis[maxn],cnt; struct edge { int to,nxt; }e[maxm<<1]; void add(int x,int y) { e[++num].to=y; e[num].nxt=last[x]; last[x]=num; } void tarjan(int x) { int i,y,tp; dfn[x]=low[x]=++cnt; st.push(x); vis[x]=1; for (i=last[x];i;i=e[i].nxt) { y=e[i].to; if (!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if (vis[y]) { low[x]=min(low[x],dfn[y]); } } if (low[x]==dfn[x]) { while (!st.empty()) { tp=st.top(); printf("%d ",tp); vis[tp]=0; st.pop(); if (tp==x) break; } printf(" "); } } int main() { int i,n,m,x,y; scanf("%d%d",&n,&m); for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); add(x,y); } for(i=1;i<=n;i++) if(!dfn[i]) tarjan(i); return 0; }
题意:给一个联通的无向图,要求从中删边让它变为连通的树,并且s节点的度不超过ds,t节点的度不超过st。
思路:将s与t从图中分离,求剩下图中的连通块,可知每个连通块只存在三种情况,①与s连边,②与t连边,③与s和t均连边。
对于只与s或t相连的连通块,直接连边即可。
对于与s和t均相连的连通块,若s与t不连通,则将连通块与s、t各连一条边;若s与t已经连通,则选择s、t中度数未超过要求的点连边(只连一条边)。
若不存在与s和t均联通的连通块,则在s与t之间连边(因为是连通图,必定有边)。
#include<cstdio> #include<cstring> #include<algorithm> #define maxn 200005 #define maxm 400005 using namespace std; int num,to[maxm<<1],nxt[maxm<<1],last[maxn]; int vis[maxn],cnt,vs[maxn],vt[maxn],s,t,tot; struct node { int x,y; }ans[maxn]; void add(int x,int y) { to[++num]=y;nxt[num]=last[x];last[x]=num; } void dfs(int u) { int i,v; vis[u]=1; for (i=last[u];i;i=nxt[i]) { v=to[i]; if (v==s) vs[cnt]=u; if (v==t) vt[cnt]=u; if (!vis[v]) { ans[++tot].x=u;ans[tot].y=v; dfs(v); } } } int main() { int i,j,x,y,n,m,ds,dt,flag=0,both=0; scanf("%d%d",&n,&m); for (i=1;i<=m;i++) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } scanf("%d%d%d%d",&s,&t,&ds,&dt); vis[s]=1;vis[t]=1; for (i=1;i<=n;i++) if (!vis[i]) { cnt++; dfs(i); } for (i=1;i<=cnt;i++) { if (vs[i] && !vt[i]) { ans[++tot].x=vs[i];ans[tot].y=s; ds--; } else if (!vs[i] && vt[i]) { ans[++tot].x=vt[i];ans[tot].y=t; dt--; } else if (!vs[i] && !vt[i]) flag=1; else both++; } if (flag || dt<=0 || ds<=0 || both+1>ds+dt) { printf("No "); return 0; } if (!both) { ans[++tot].x=s;ans[tot].y=t; } else { flag=0; for (i=1;i<=cnt;i++) if (vs[i] && vt[i]) { if (!flag) { ans[++tot].x=vs[i];ans[tot].y=s; ans[++tot].x=vt[i];ans[tot].y=t; flag=1; ds--;dt--; } else { if (ds) { ans[++tot].x=vs[i];ans[tot].y=s; ds--; } else { ans[++tot].x=vt[i];ans[tot].y=t; dt--; } } } } printf("Yes "); for (i=1;i<=tot;i++) printf("%d %d ",ans[i].x,ans[i].y); return 0; }
G ZOJ 4097
I UVA 1108