題目大意:
給出一個有向圖n個頂點m條邊,判斷是否能任意選擇兩個點u,v,都至少存在一條通路從u到達v或v到達u,也就是u,v之間存在單向的通路。
分析:
首先将有向圖的極大強連通分量收縮成一個點,構成新的有向無環圖G'。現在要判斷新圖G'是一個單連通圖。即每對頂點u,v存在u->v或v->u或兩者都存在。
這個條件看起來很面熟,貌似競賽圖就是滿足這樣條件的圖。競賽圖有一個性質,競賽圖必然存在一條哈密爾頓通路,即可以存在一條極長的單向鍊把所有的頂點串起來。是以此題隻需要求最長的單向鍊即可。
此題的關鍵在于收縮強連通分支,求最長鍊用簡單的DP就好。
- #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;
- }