图论
1.二分图最大匹配数=最小覆盖数:(1.每条匹配边之间都是独立的,没有重合的X部点或者Y部点,所以,只对于匹配边而言,每条匹配边都需要一个覆盖点,才能覆盖这条边。(2.http://blog.sina.com.cn/s/blog_51cea4040100h152.html 证明1可知该点集必定可以覆盖掉二分图中全部的边。(如果连有未匹配点的匹配点,则选该匹配点,此时另一个匹配点必定不可能连有未匹配点,因此随便取一个即可。得证。
poj1469:裸求max_match
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)){ if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } int tmp,to; struct max_match{ int p,n,left[305]; bool vis[305],g[105][305]; void init() { clr(g,false);clr(left,-1); } bool match(int i){ rep(j,n) if(g[i][j]&&!vis[j]){ vis[j]=true; if(left[j]==-1||match(left[j])){ left[j]=i;return true; } } return false; } int solve(){ int ans=0; rep(i,p){ clr(vis,0);if(match(i)) ans++; } return ans; } }mm; int main(){ int t=read(); while(t--){ mm.init();bool ok=true; mm.p=read(),mm.n=read(); rep(i,mm.p){ tmp=read(); rep(j,tmp) to=read(),mm.g[i][to]=true; } if(!tmp) ok=false; if(ok) if(mm.solve()==mm.p) printf("YES\n");else printf("NO\n"); else printf("NO\n"); } return 0; }
poj2446:用2*1对有空洞的矩形进行覆盖。。。数据好弱。。。懒得理了。。。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) int x;char c; int read(){ c=getchar();x=0; while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=1000; const int maxn=5000; const int inf=0x7f7f7f7f; int n,m,s,t,ans,p; bool map[nmax][nmax]; struct max_match{ bool g[maxn][maxn],vis[maxn]; int left[maxn]; void init(){ clr(g,false);clr(left,-1);} bool match(int x){ rep(i,n*m) if(g[x][i]&&!vis[i]){ vis[i]=true; if(left[i]==-1||match(left[i])){ left[i]=x;return true; } } return false; } int solve(){ ans=0; rep(i,n*m) { clr(vis,false);if(match(i)) ans++; } return ans; } }mm; int xx[5]={0,0,0,1,-1}; int yy[5]={0,1,-1,0,0}; int main(){ clr(map,true);mm.init(); n=read(),m=read(),p=read(); rep(i,p) s=read(),t=read(),map[t][s]=false; rep(i,n) rep(j,m) if(map[i][j]&&((i+j)%2)){ rep(k,4) { s=i+xx[k],t=j+yy[k]; if(map[s][t]&&s&&t&&s<=n&&t<=m) mm.g[m*(i-1)+j][m*(s-1)+t]=true; } } /*rep(i,n) { rep(j,m) { if(map[i][j]) printf("1 ");else printf("0 "); } printf("\n"); } rep(i,n*m){ rep(j,n*m){ if(mm.g[i][j]) printf("%d %d:1\n",i,j);else printf("%d %d:0\n",i,j); } printf("\n"); }*/ printf("%s\n",mm.solve()*2==(n*m-p)?"YES":"NO"); return 0; }
poj1274:简单求最大匹配
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } int n,m,ans,tmp,t; const int nmax=305; struct max_match{ bool vis[nmax],g[nmax][nmax]; int left[nmax]; void init(){ clr(g,false);clr(left,-1);ans=0; } bool match(int x){ rep(i,m){ if(g[x][i]&&!vis[i]){ vis[i]=true; if(left[i]==-1||match(left[i])){ left[i]=x;return true; } } } return false; } int solve(){ rep(i,n) { clr(vis,0); if(match(i)) ans++; } return ans; } }mm; int main(){ // freopen("test.out","w",stdout); while(scanf("%d%d",&n,&m)==2){ mm.init(); rep(i,n){ tmp=read(); rep(j,tmp) t=read(),mm.g[i][t]=true; } printf("%d\n",mm.solve()); } return 0; }
hdu2063:还是裸求最大匹配。。。然而那些0k的是怎么做到的orzorz求指导。。。
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) int x;char c; int read(){ x=0;c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=1005; const int maxn=505; const int inf=0x7f7f7f7f; struct edge{ int to;edge *next; }; edge edges[nmax],*pt=edges,*head[maxn]; int lft[maxn],n,m,k,u,v;bool vis[maxn]; void add(int s,int t){ pt->to=t;pt->next=head[s];head[s]=pt++; } void init(){ clr(head,0);clr(lft,-1);pt=edges; } bool match(int x){ qwq(x){ int to=o->to; if(vis[to]) continue; vis[to]=true; if(lft[to]==-1||match(lft[to])){ lft[to]=x;return true; } } return false; } int solve(){ int ans=0; rep(i,n) { clr(vis,0);if(match(i)) ans++; } return ans; } int main(){ while(1){ k=read();if(!k) break;n=read(),m=read(); init(); rep(i,k) u=read(),v=read(),add(u,v); printf("%d\n",solve()); } return 0; }
poj3041:白书原题。。。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=10005; const int maxn=505; const int inf=0x7f7f7f7f; struct edge{ int to;edge *next; }; edge edges[nmax],*pt,*head[nmax]; void add(int s,int t){ pt->to=t;pt->next=head[s];head[s]=pt++; } int lft[maxn],n,k;bool vis[maxn]; bool match(int x){ qwq(x){ int to=o->to; if(vis[to]) continue; vis[to]=true; if(lft[to]==-1||match(lft[to])){ lft[to]=x;return true; } } return false; } int solve(){ int ans=0; rep(i,n) { clr(vis,false);if(match(i)) ans++; } return ans; } int main(){ n=read(),k=read(); clr(head,0);pt=edges;clr(lft,-1); rep(i,k){ int s=read(),t=read();add(s,t); } printf("%d\n",solve()); return 0; }
(1:最大独立集 = n(图节点总数)-最小覆盖数=n-最大匹配数
(2:有一种求二分图中的关键边的将每一条边删除在跑一次就可以了。。。懒得写了。。。
(3:DAG最小路径覆盖数:点不重复的情况下遍历玩DAG中所有点的最小路径数:将每个点拆成两个点。(1:每个点不能遍历两次,符合求最大匹配;(2:匹配点有后继,不是结尾节点。所以非匹配点就是结尾节点。即DAG的最小路径覆盖数=DAG图中的节点数-相应二分图中的最大匹配数
(4:KM算法最优匹配:前提是二部图。即左右点数相同。若相同子图存在完美匹配,则必定为最优匹配,然后不断地update找完美匹配就可以了。
hdu2255:最优匹配模板
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)) { if(c=='-') f=false; c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } const int nmax=305; const int inf=0x7f7f7f7f; int lx[nmax],ly[nmax],match[nmax],vx[nmax],vy[nmax],w[nmax][nmax],slack[nmax],ans,n; bool findpath(int x){ vx[x]=1; rep(y,n){ if(vy[y]) continue; if(w[x][y]==lx[x]+ly[y]){ vy[y]=1; if(!match[y]||findpath(match[y])){ match[y]=x;return true; } }else slack[y]=min(slack[y],lx[x]+ly[y]-w[x][y]); } return false; } void km(){ clr(match,0);clr(lx,0);clr(ly,0); rep(i,n) rep(j,n) lx[i]=max(lx[i],w[i][j]); rep(x,n){ clr(slack,0x7f); while(1){ clr(vx,0);clr(vy,0); if(findpath(x)) break; int tmp=inf; rep(i,n) if(!vy[i]) tmp=min(tmp,slack[i]); if(tmp==inf) return ; rep(i,n){ if(vx[i]) lx[i]-=tmp; if(vy[i]) ly[i]+=tmp; else slack[i]-=tmp; } } } } int main(){ while(scanf("%d",&n)==1){ ans=0; rep(i,n) rep(j,n) w[i][j]=read(); km(); rep(i,n) ans+=w[match[i]][i]; printf("%d\n",ans); } return 0; }
hdu1853:有向图中文如果所有的点都恰好被一个或多个不相交的环所覆盖,求最小权值和。不相交,看成二分图最优匹配就好了。如果满足,则是完美匹配。不满足,有些点为未匹配点,可判断。还是同样每个点拆成左右两个点。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define REP(i,s,t) for(int i=s;i<=t;i++) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)){ if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } const int nmax=105; const int inf=0x7f7f7f7f; int w[nmax][nmax],lx[nmax],ly[nmax],match[nmax],slack[nmax],vx[nmax],vy[nmax],n,m,ans,tmp,u,v,d; bool findpath(int x){ vx[x]=1; rep(y,n){ if(vy[y]) continue; if(w[x][y]==lx[x]+ly[y]){ vy[y]=1; if(!match[y]||findpath(match[y])){ match[y]=x;return true; } }else slack[y]=min(slack[y],lx[x]+ly[y]-w[x][y]); } return false; } void km(){ clr(match,0);clr(lx,0);clr(ly,0); rep(i,n) rep(j,n) lx[i]=max(lx[i],w[i][j]); rep(x,n){ clr(slack,0x7f); while(1){ clr(vx,0);clr(vy,0); if(findpath(x)) break; tmp=inf; rep(i,n) if(!vy[i]) tmp=min(tmp,slack[i]); if(tmp==inf) return ; rep(i,n){ if(vx[i]) lx[i]-=tmp; if(vy[i]) ly[i]+=tmp;else slack[i]-=tmp; } } } } int main(){ while(scanf("%d%d",&n,&m)==2){ REP(i,0,n) REP(j,0,n) w[i][j]=-inf; rep(i,m){ u=read(),v=read(),d=read();w[u][v]=max(w[u][v],-d); } /*rep(i,n) { rep(j,n) printf("%d ",w[i][j]); printf("\n"); }*/ km();ans=0; //rep(i,n) printf("%d ",match[i]); rep(i,n){ if(w[match[i]][i]==-inf) { ans=1;break; }else ans+=w[match[i]][i]; } printf("%d\n",-ans); } return 0; }
2.求割顶/桥:poj1144:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) #define adde(u,v) add(u,v),add(v,u) const int nmax=105; int n,s,t,ans,dfs_clock; struct edge{ int to;edge *next; }; edge edges[nmax<<2],*pt,*head[nmax]; int pre[nmax],low[nmax]; bool iscut[nmax];char ch[100]; void add(int s,int t){ pt->to=t;pt->next=head[s];head[s]=pt++;} int dfs(int u,int fa){ int lowu=pre[u]=++dfs_clock,child=0; qwq(u){ int v=o->to; if(!pre[v]){ child++;int lowv=dfs(v,u);lowu=min(lowu,lowv); if(lowv>=pre[u]) iscut[u]=true; }else if(pre[v]<pre[u]&&v!=fa) lowu=min(lowu,pre[v]); } if(fa<0&&(child==1)) iscut[u]=false; return low[u]=lowu; } int get(char *s){ int x=0; for(int i=0;s[i];i++) x=x*10+s[i]-'0'; return x; } int main(){ while(scanf("%d",&n)==1&&n){ dfs_clock=0;clr(pre,0);clr(iscut,0);pt=edges;clr(head,0); while(scanf("%s",ch)==1){ if(ch[0]=='0') break; s=get(ch); while(scanf("%s",ch)==1){ t=get(ch);adde(s,t); if(getchar()=='\n') break; } } dfs(1,-1);ans=0; rep(i,n) if(iscut[i]) ans++; printf("%d\n",ans); } return 0; }
poj2117:求去掉一个点后最多分为多少块。。。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) #define adde(u,v) add(u,v),add(v,u) const int nmax=10005; const int inf=0x7f7f7f7f; int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)) { if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } struct edge{ int to;edge *next; }; edge edges[nmax*nmax],*pt,*head[nmax]; void add(int u,int v){ pt->to=v;pt->next=head[u];head[u]=pt++; } int n,m,s,t,ans,sum,dfs_clock; int cnt[nmax],low[nmax],pre[nmax]; int dfs(int u,int fa){ int lowu=pre[u]=++dfs_clock; qwq(u){ if(!pre[o->to]) { int lowv=dfs(o->to,u);lowu=min(lowu,lowv); if(lowv>=pre[u]) cnt[u]++; }else if(pre[o->to]<pre[u]&&o->to!=fa) lowu=min(lowu,pre[o->to]); } return low[u]=lowu; } int main(){ while(scanf("%d%d",&n,&m)==2&&n+m){ pt=edges;clr(head,0); dfs_clock=0,ans=-1,sum=0;clr(pre,0);clr(cnt,0); rep(i,m) s=read(),t=read(),adde(s+1,t+1); rep(i,n) if(!pre[i]) sum++,dfs(i,-1),cnt[i]--; rep(i,n) ans=max(ans,sum+cnt[i]); printf("%d\n",ans); } return 0; }
3.无向图求点双连通分量:hdu3749:(不知道不用vector怎么写。。。用vector太慢了。。。不过排60+。。。而且这道题边stack直接保存点就好吧?酱紫会快一点?。。。
#include<cstdio> #include<cstring> #include<vector> #include<stack> #include<iostream> #include<algorithm> using namespace std; #define clr(x,c) memset(x,c,sizeof(x)) #define rep(i,n) for(int i=1;i<=n;i++) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)){ if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } const int nmax=5005; int n,m,q,bcc_cnt,dfs_clock; int pre[nmax],bccno[nmax],fa[nmax]; bool iscut[nmax]; vector<int>g[nmax],bcc[nmax],belong[nmax]; struct edge{ int s,t; edge(int s,int t):s(s),t(t){} }; stack<edge>s; int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } int dfs(int u,int fa){ int lowu=pre[u]=++dfs_clock; for(int i=0;i<g[u].size();i++){ int v=g[u][i];edge e=edge(u,v); if(v==fa) continue; if(!pre[v]){ s.push(e); int lowv=dfs(v,u); lowu=min(lowu,lowv); if(lowv>=pre[u]){ bcc_cnt++;bcc[bcc_cnt].clear(); while(1){ edge x=s.top();s.pop(); if(bccno[x.s]!=bcc_cnt){ bcc[bcc_cnt].push_back(x.s); bccno[x.s]=bcc_cnt; belong[x.s].push_back(bcc_cnt); } if(bccno[x.t]!=bcc_cnt){ bcc[bcc_cnt].push_back(x.t); bccno[x.t]=bcc_cnt; belong[x.t].push_back(bcc_cnt); } if(x.s==u&&x.t==v) break; } } }else if(pre[v]<pre[u]) s.push(e),lowu=min(lowu,pre[v]); } return lowu; } int main(){ int kase=0; while(scanf("%d%d%d",&n,&m,&q)==3&&n){ int s,t; bcc_cnt=dfs_clock=0;clr(pre,0);clr(bccno,0); rep(i,n) g[i].clear(),belong[i].clear(),fa[i]=i; rep(i,m){ s=read(),t=read(),s++,t++,g[s].push_back(t);g[t].push_back(s); s=find(s),t=find(t);if(s!=t) fa[s]=t; } // rep(i,n) printf("%d ",fa[i]); rep(i,n) if(!pre[i]) dfs(i,-1); printf("Case %d:\n",++kase); rep(i,q){ s=read(),t=read();s++,t++; if(find(s)!=find(t)) printf("zero\n"); else{ bool f=false; for(int j=0;j<belong[s].size()&&!f;j++) for(int k=0;k<belong[t].size()&&!f;k++) if(belong[s][j]==belong[t][k]) if(bcc[belong[s][j]].size()>2) printf("two or more\n"),f=true; if(!f) printf("one\n"); } } } return 0; }
4.有向图的强连通分量:hdu2767:把一部分放在外面是因为无向图中一个点可以是多个点双连通分量的,有向图的每个点只属于一个。。证明抄自网上:一个含n个点的图,至少要有n条边,才能强连通。即每一个点至少都会有一个入度和出度。对于得到的DAG,设有a个结点的入度为0, b个结点的出度为0,因为增加一条边会同时增加一个入度和一个出度,因此要强连通,即,要想消去所有入度或出度为0的点,至少要 max{a,b}条边。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<stack> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)){ if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } const int nmax=50005; const int inf=0x7f7f7f7f; struct edge{ int to;edge *next; }; edge edges[nmax<<1],*pt,*head[nmax]; int pre[nmax],low[nmax],sccno[nmax]; bool in[nmax],out[nmax]; int n,m,dfs_clock,scc_cnt; stack<int>s; void add(int s,int t){ pt->to=t;pt->next=head[s];head[s]=pt++; } int dfs(int u){ int lowu=pre[u]=++dfs_clock;s.push(u); qwq(u){ int to=o->to; if(!pre[to]) lowu=min(lowu,dfs(to)); else if(!sccno[to]) lowu=min(lowu,pre[to]); } if(lowu==pre[u]){ scc_cnt++; while(1){ int x=s.top();s.pop(); sccno[x]=scc_cnt; if(x==u) break; } } return lowu; } int main(){ int t=read(); while(t--){ clr(sccno,0);clr(in,false),clr(out,false);clr(pre,0); pt=edges;clr(head,0);dfs_clock=scc_cnt=0; n=read(),m=read(); rep(i,m){ int s=read(),t=read();add(s,t); } rep(i,n) if(!pre[i]) dfs(i); rep(i,n){ qwq(i) if(sccno[i]!=sccno[o->to]) out[sccno[i]]=true,in[sccno[o->to]]=true; } int a=0,b=0; rep(i,scc_cnt) { if(!in[i]) a++;if(!out[i]) b++; } if(scc_cnt==1) printf("0\n"); else printf("%d\n",max(a,b)); } return 0; }
poj1236:同上一题。。。忘了输出scc_cnt=1的情况一直WAqwq
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<stack> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)) { if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } const int nmax=105; const int inf=0x7f7f7f7f; stack<int>s; struct edge{ int to;edge *next; }; edge edges[nmax*nmax*2],*pt=edges,*head[nmax]; void add(int s,int t){ pt->to=t;pt->next=head[s];head[s]=pt++; } int pre[nmax],sccno[nmax]; int dfs_clock,scc_cnt,n; bool in[nmax],out[nmax]; int dfs(int x){ int lowu=pre[x]=++dfs_clock;s.push(x); qwq(x){ int to=o->to; if(!pre[to]) lowu=min(lowu,dfs(to)); else if(!sccno[to]) lowu=min(lowu,pre[to]); } if(lowu==pre[x]){ scc_cnt++; while(1){ int e=s.top();s.pop(); sccno[e]=scc_cnt; if(e==x) break; } } return lowu; } int main(){ n=read(); int to;scc_cnt=dfs_clock=0; pt=edges;clr(head,0);clr(pre,0);clr(sccno,0);clr(in,false);clr(out,false); rep(i,n){ while(1){ to=read(); if(!to) break; add(i,to); } } /*rep(i,n){ qwq(i) printf("%d ",o->to);printf("\n"); }*/ rep(i,n) if(!pre[i]) dfs(i); rep(i,n) qwq(i) { if(sccno[i]!=sccno[o->to]) in[sccno[o->to]]=true,out[sccno[i]]=true; } int a=0,b=0; rep(i,scc_cnt) { if(!in[i]) a++; if(!out[i]) b++; } if(scc_cnt==1) printf("1\n0\n"); else printf("%d\n%d\n",a,max(a,b)); return 0; }
hdu1269:判断是否是连通图。。。感觉这样子跑还是多跑了很多没用的啊。。。不过水过去就算了。。。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<stack> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)) { if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } const int nmax=10005; const int maxn=100005; struct edge{ int to;edge *next; }; edge edges[maxn<<1],*pt,*head[nmax]; void add(int s,int t){ pt->to=t;pt->next=head[s];head[s]=pt++; } int pre[nmax],sccno[nmax],dfs_clock,scc_cnt,n,m,ss,t; stack<int>s; void init(){ clr(pre,0);clr(sccno,0);clr(head,0);pt=edges;dfs_clock=scc_cnt=0; } int dfs(int x){ int lowu=pre[x]=++dfs_clock;s.push(x); qwq(x){ int to=o->to; if(!pre[to]) lowu=min(lowu,dfs(to)); else if(!sccno[to]) lowu=min(lowu,pre[to]); } if(lowu>=pre[x]){ scc_cnt++; while(1){ int e=s.top();s.pop(); sccno[e]=scc_cnt; if(e==x) break; } } return lowu; } int main(){ while(scanf("%d%d",&n,&m)==2&&n+m){ init(); rep(i,m) ss=read(),t=read(),add(ss,t); dfs(1);bool f=true; rep(i,n) if(!pre[i]) f=false; if(scc_cnt>1) f=false; if(f) printf("Yes\n");else printf("No\n"); } return 0; }
poj2762:判断图中是否任意两个点都有路径相通。。。网上结论说应该是一条链。画了好久好像是找不到反例。。。然后一直WA。。。不想调。。。算了挖个坑吧。。。
WA code #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<stack> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define qwq(x) for(edge *o=head[x];o;o=o->next) #define qaq(x) for(edge *o=h[x];o;o=o->next) int read(){ int x=0;char c=getchar();bool f=true; while(!isdigit(c)) { if(c=='-') f=false;c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return f?x:-x; } const int nmax=1005; const int maxn=6005; struct edge{ int to;edge *next; }; edge edges[maxn<<1],*pt,*head[nmax],e[maxn<<1],*h[nmax]; int pre[nmax],sccno[nmax],in[nmax],dfs_clock,scc_cnt,n,m,u,v; bool map[nmax][nmax]; void add(int u,int v){ pt->to=v;pt->next=head[u];head[u]=pt++; } void adde(int u,int v){ pt->to=v;pt->next=h[u];h[u]=pt++; } stack<int>s,q; int dfs(int x){ int lowu=pre[x]=++dfs_clock;s.push(x); qwq(x){ int to=o->to; if(!pre[to]) lowu=min(lowu,dfs(to)); else if(!sccno[to]) lowu=min(lowu,pre[to]); } if(lowu>=pre[x]){ scc_cnt++; while(1){ int tmp=s.top();s.pop(); sccno[tmp]=scc_cnt; if(tmp==x) break; } } return lowu; } bool topo(){ rep(i,scc_cnt) if(!in[i]) q.push(i); int sum=0; while(!q.empty()){ if(q.size()>1) return false; int x=q.top();q.pop();sum++; qaq(x) if(--in[o->to]==0) q.push(o->to); } return sum==scc_cnt; } void init(){ clr(pre,0);clr(sccno,0);clr(head,0);pt=edges;clr(h,0);pt=e;dfs_clock=scc_cnt=0;clr(map,0); } int main(){ int t=read(); while(t--){ n=read(),m=read();init(); rep(i,m) u=read(),v=read(),add(u,v); rep(i,n) if(!pre[i]) dfs(i); rep(i,n) qwq(i){ if(sccno[i]!=sccno[o->to]&&!map[i][o->to]) adde(sccno[i],sccno[o->to]),in[sccno[o->to]]++,map[i][o->to]=true; } if(topo()) printf("Yes\n");else printf("No\n"); } return 0; }