题目大意:
给出一个有向图n个顶点m条边,判断是否能任意选择两个点u,v,都至少存在一条通路从u到达v或v到达u,也就是u,v之间存在单向的通路。
分析:
首先将有向图的极大强连通分量收缩成一个点,构成新的有向无环图G'。现在要判断新图G'是一个单连通图。即每对顶点u,v存在u->v或v->u或两者都存在。
这个条件看起来很面熟,貌似竞赛图就是满足这样条件的图。竞赛图有一个性质,竞赛图必然存在一条哈密尔顿通路,即可以存在一条极长的单向链把所有的顶点串起来。所以此题只需要求最长的单向链即可。
此题的关键在于收缩强连通分支,求最长链用简单的DP就好。
- /*
- PKU2762
- */
- #include <stdio.h>
- #include <memory.h>
- #define clr(a) memset(a,0,sizeof(a))
- #define N 1005
- #define M 15005
- typedef struct StrNode{
- int j; struct StrNode* next;
- }Node;
- int memp; Node mem[M]; //M>=2*|E|
- void addEdge(Node* e[],int i,int j){
- Node* p = &mem[memp++];
- p->j=j; p->next=e[i]; e[i]=p;
- }
- int g_DFS_First;
- void DFS_conn(Node* e[],int i,int mark[],int f[],int* nf){
- int j; Node* p;
- if(mark[i]) return; else mark[i]=1;
- if(!g_DFS_First) f[i]=*nf; //反向搜索,获取连通分量编号
- for(p=e[i];p!=NULL;p=p->next) DFS_conn(e,p->j,mark,f,nf);
- if(g_DFS_First) f[(*nf)++]=i; //正向搜索,获取时间戳
- }
- int Connection (Node* e[],int n,int con[]){
- int i,j,k,mark[N],ncon,time[N],ntime;//time[i]表示时间戳为i的节点
- Node *p,*re[N]; //反向边
- clr(re); //构造反向边邻接表
- for(i=0;i<n;i++) for(p=e[i];p!=NULL;p=p->next) addEdge(re,p->j,i);
- g_DFS_First = 1; //正向DFS,获得时间戳
- clr(mark); clr(time); ntime=0;
- for(i=0;i<n;i++) if(!mark[i]) DFS_conn(e,i,mark,time,&ntime);
- g_DFS_First = 0; //反向DFS,获得强连通分量
- clr(mark); clr(con); ncon=0;
- for(i=n-1;i>=0;i--) if(!mark[time[i]])
- { DFS_conn(re,time[i],mark,con,&ncon); ncon++; }
- return ncon;
- }
- int ShrinkConnection(Node *e[],int n,Node *ce[],int con[]){
- int i,j,k,m; Node *p,*q;
- m=Connection(e,n,con);
- for(i=0;i<m;i++) ce[i]=NULL;
- for(k=0;k<n;k++) for(i=con[k],p=e[k];p!=NULL;p=p->next){
- for(j=con[p->j],q=ce[i];q!=NULL;q=q->next) if(q->j==j) break;
- if(q==NULL&&i!=j) addEdge(ce,i,j);
- }
- return m;
- }
- /********************/
- int n,m,nc;
- int con[N],f[N];
- Node *e[N];
- Node *ce[N];
- #define MAX(a,b) ((a)>(b)?(a):(b))
- int DFS_link(Node* e[],int i,int f[]){
- int j,k,max=1; Node *p;
- for(p=e[i];p!=NULL;p=p->next){
- if(f[p->j]) max=MAX(max,f[p->j]+1);
- else{
- k=DFS_link(e,p->j,f);
- max=MAX(max,k+1);
- }
- }
- return f[i]=max;
- }
- int main()
- {
- int i,j,k,ans,T;
- scanf("%d",&T);
- while(T--){
- //init
- memp=0; clr(e);
- //input
- scanf("%d%d",&n,&m);
- for(k=0;k<m;k++){
- scanf("%d%d",&i,&j);
- addEdge(e,i-1,j-1);
- }
- //Shrink Connection
- nc=ShrinkConnection(e,n,ce,con);
- //maxlen link
- clr(f); ans=1;
- for(i=0;i<nc;i++) if(!f[i]){
- k=DFS_link(ce,i,f);
- ans=MAX(ans,k);
- }
- if(ans==nc) puts("Yes");
- else puts("No");
- }
- return 0;
- }