PKU 2762 Going from u to v or from v to u? - 单连通图判定

题目大意:

给出一个有向图n个顶点m条边,判断是否能任意选择两个点u,v,都至少存在一条通路从u到达v或v到达u,也就是u,v之间存在单向的通路。

分析:

首先将有向图的极大强连通分量收缩成一个点,构成新的有向无环图G'。现在要判断新图G'是一个单连通图。即每对顶点u,v存在u->v或v->u或两者都存在。

这个条件看起来很面熟,貌似竞赛图就是满足这样条件的图。竞赛图有一个性质,竞赛图必然存在一条哈密尔顿通路,即可以存在一条极长的单向链把所有的顶点串起来。所以此题只需要求最长的单向链即可。

此题的关键在于收缩强连通分支,求最长链用简单的DP就好。

 

  1. /*
  2. PKU2762
  3. */
  4. #include <stdio.h>
  5. #include <memory.h>
  6. #define clr(a) memset(a,0,sizeof(a))
  7. #define N 1005
  8. #define M 15005
  9. typedef struct StrNode{
  10.     int j; struct StrNode* next;
  11. }Node;
  12. int memp; Node mem[M]; //M>=2*|E|
  13. void addEdge(Node* e[],int i,int j){
  14.     Node* p = &mem[memp++];
  15.     p->j=j; p->next=e[i]; e[i]=p;
  16. }
  17. int g_DFS_First;
  18. void DFS_conn(Node* e[],int i,int mark[],int f[],int* nf){
  19.     int j; Node* p;
  20.     if(mark[i]) returnelse mark[i]=1;
  21.     if(!g_DFS_First) f[i]=*nf;  //反向搜索,获取连通分量编号
  22.     for(p=e[i];p!=NULL;p=p->next) DFS_conn(e,p->j,mark,f,nf);
  23.     if(g_DFS_First) f[(*nf)++]=i;   //正向搜索,获取时间戳
  24. }
  25. int Connection (Node* e[],int n,int con[]){
  26.     int i,j,k,mark[N],ncon,time[N],ntime;//time[i]表示时间戳为i的节点
  27.     Node *p,*re[N]; //反向边
  28.     clr(re);        //构造反向边邻接表
  29.     for(i=0;i<n;i++) for(p=e[i];p!=NULL;p=p->next) addEdge(re,p->j,i);
  30.     g_DFS_First = 1;    //正向DFS,获得时间戳 
  31.     clr(mark); clr(time); ntime=0;
  32.     for(i=0;i<n;i++) if(!mark[i]) DFS_conn(e,i,mark,time,&ntime);
  33.     
  34.     g_DFS_First = 0;    //反向DFS,获得强连通分量
  35.     clr(mark); clr(con); ncon=0;
  36.     for(i=n-1;i>=0;i--) if(!mark[time[i]])
  37.     { DFS_conn(re,time[i],mark,con,&ncon); ncon++; }
  38.     
  39.     return ncon;
  40. }
  41. int ShrinkConnection(Node *e[],int n,Node *ce[],int con[]){
  42.     int i,j,k,m; Node *p,*q;
  43.     m=Connection(e,n,con);
  44.     for(i=0;i<m;i++) ce[i]=NULL;
  45.     for(k=0;k<n;k++) for(i=con[k],p=e[k];p!=NULL;p=p->next){
  46.         for(j=con[p->j],q=ce[i];q!=NULL;q=q->next) if(q->j==j) break;
  47.         if(q==NULL&&i!=j) addEdge(ce,i,j);
  48.     }
  49.     return m;
  50. }
  51. /********************/
  52. int n,m,nc;
  53. int con[N],f[N];
  54. Node *e[N];
  55. Node *ce[N];
  56. #define MAX(a,b) ((a)>(b)?(a):(b))
  57. int DFS_link(Node* e[],int i,int f[]){
  58.     int j,k,max=1; Node *p;
  59.     for(p=e[i];p!=NULL;p=p->next){
  60.         if(f[p->j]) max=MAX(max,f[p->j]+1);
  61.         else{
  62.             k=DFS_link(e,p->j,f);
  63.             max=MAX(max,k+1);
  64.         }
  65.     }
  66.     return f[i]=max;
  67. }
  68. int main()
  69. {
  70.     int i,j,k,ans,T;
  71.     
  72.     scanf("%d",&T);
  73.     while(T--){
  74.         //init
  75.         memp=0; clr(e);
  76.         //input
  77.         scanf("%d%d",&n,&m);
  78.         for(k=0;k<m;k++){
  79.             scanf("%d%d",&i,&j);
  80.             addEdge(e,i-1,j-1);
  81.         }
  82.         //Shrink Connection
  83.         nc=ShrinkConnection(e,n,ce,con);
  84.         //maxlen link
  85.         clr(f); ans=1;
  86.         for(i=0;i<nc;i++) if(!f[i]){
  87.             k=DFS_link(ce,i,f);
  88.             ans=MAX(ans,k);
  89.         }
  90.         if(ans==nc) puts("Yes");
  91.         else puts("No");
  92.     }
  93.     
  94.     return 0;
  95. }

你可能感兴趣的:(PKU 2762 Going from u to v or from v to u? - 单连通图判定)