poj3694 先e-DCC缩点,此时图就变成了树,树上每一条边都是桥。对于添加边的操作,相当于和树上一条路径构环,导致该路径上所有边都不成为桥。那么找这条新加边的最近公共祖先,把路径上的所有没被删掉的桥的数量计算出来,未操作之前桥的个数减去该值就是当前答案。中间因为一条边会多次删除,没有意义,可以采取并查集路径压缩的思想,直接指向下一个没有被删的桥
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[4100000];int len,last[1100000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int z,dfn[1100000],low[1100000]; bool b[1100000]; void tarjan(int x,int fr) { dfn[x]=low[x]=++z; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(dfn[y]==0) { tarjan(y,x); low[x]=min(low[x],low[y]); if(dfn[x]<low[y]) b[k]=b[k^1]=true; } if(y!=fr) low[x]=min(low[x],dfn[y]); } } int cnt,bel[1100000]; void sdfj(int x,int fr) { bel[x]=cnt; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(bel[y]==0&&b[k]==false) sdfj(y,x); } } //--------------------缩点---------------------- int Bin[25]; int f[25][1100000],dep[1100000]; void dfs(int x) { for(int i=1;dep[x]>=Bin[i];i++)f[i][x]=f[i-1][f[i-1][x]]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=f[0][x]) { f[0][y]=x; dep[y]=dep[x]+1; dfs(y); } } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=22;i>=0;i--) if(dep[x]-dep[y]>=Bin[i])x=f[i][x]; if(x==y)return x; for(int i=22;i>=0;i--) if(dep[x]>=Bin[i]&&f[i][x]!=f[i][y])x=f[i][x],y=f[i][y]; return f[0][x]; } //--------------get_LCA---------------------------- int fa[1100000];bool v[1100000]; int main() { int n,m,T_T=0; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; printf("Case %d: ",++T_T); len=1;memset(last,0,sizeof(last)); int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } z=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(b,false,sizeof(b)); tarjan(1,0); cnt=0; memset(bel,0,sizeof(bel)); for(int i=1;i<=n;i++) if(bel[i]==0) cnt++, sdfj(i,0); int tp=0; memset(last,0,sizeof(last)); for(int i=1;i<=len;i++) { if(bel[a[i].x]!=bel[a[i].y]) { tp++; a[tp].x=bel[a[i].x]; a[tp].y=bel[a[i].y]; a[tp].next=last[a[tp].x]; last[a[tp].x]=tp; } } len=tp; Bin[0]=1;for(int i=1;i<=22;i++)Bin[i]=Bin[i-1]*2; f[0][1]=0;dep[1]=0;dfs(1); for(int i=1;i<=cnt;i++)fa[i]=f[0][i]; memset(v,false,sizeof(v)); int Q,ans=cnt-1; scanf("%d",&Q); while(Q--) { scanf("%d%d",&x,&y);x=bel[x],y=bel[y]; int lca=LCA(x,y),t; while(dep[x]>dep[lca]) { if(v[x]==false){ans--;v[x]=true;} t=fa[x]; if(dep[fa[x]]<dep[lca])fa[x]=lca; x=t; } while(dep[y]>dep[lca]) { if(v[y]==false){ans--;v[y]=true;} t=fa[y]; if(dep[fa[y]]<dep[lca])fa[y]=lca; y=t; } printf("%d ",ans); } printf(" "); } return 0; }
poj2942 建补图,也就是可以坐在一起的连边。对于一次会议,上面坐着的骑士在图中就是一个简单环,所以这道题其实就是找那些没有在任何奇环中的点。找出所有的v-DCC,用黑白染色判即可。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[1100000];int len,last[1100]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int tim,ti[1100]; bool col[1100],v[1100]; bool findodd(int x) { for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(ti[y]==tim) { if(v[y]==false) { v[y]=true; col[y]=col[x]^1; if(findodd(y))return true; } else if(col[y]==col[x])return true; } } return false; } int z,dfn[1100],low[1100]; int top,sta[1100],hlen,h[1100]; bool inodd[1100]; void v_DCC(int x,int fr) { dfn[x]=low[x]=++z;sta[++top]=x; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(dfn[y]==0) { v_DCC(y,x); low[x]=min(low[x],low[y]); if(dfn[x]<=low[y]) { int k;tim++;hlen=0; do { k=sta[top];top--; h[++hlen]=k; ti[k]=tim;v[k]=false; }while(k!=y); if(dfn[x]==low[y]) { h[++hlen]=x; ti[x]=tim;v[x]=false; } col[y]=0; if(findodd(y)) { for(int i=1;i<=hlen;i++) inodd[h[i]]=true; } } } else if(y!=fr) low[x]=min(low[x],dfn[y]); } } bool mp[1100][1100]; int main() { int n,m,x,y; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; memset(mp,true,sizeof(mp)); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); mp[x][y]=mp[y][x]=false; } len=0;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j&&mp[i][j]==true)ins(i,j); z=0;top=0;tim=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(inodd,false,sizeof(inodd)); memset(ti,0,sizeof(ti)); for(int i=1;i<=n;i++) if(dfn[i]==0)v_DCC(i,0); int ans=0; for(int i=1;i<=n;i++) if(inodd[i]==false)ans++; printf("%d ",ans); } return 0; }
poj2230 欧拉回路裸题。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[110000];int len,last[11000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int top,sta[110000],cur[11000]; bool v[110000]; int aslen,as[110000]; void euler() { top=0;sta[++top]=1; memcpy(cur,last,sizeof(cur)); while(top!=0) { int x=sta[top],k; for(k=cur[x];k;k=a[k].next); if(k) { sta[++top]=a[k].y; cur[x]=a[k].next; } else top--,as[++aslen]=x; } } int main() { int n,m,x,y; scanf("%d%d",&n,&m); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } euler(); for(int i=aslen;i>=1;i--)printf("%d ",as[i]); return 0; }