題意是給出一些點,和他們之間的有向邊,如果圖中任意兩點 x,y 之間滿足 x 可以到達 y 或者 y 可以到達 x ,就輸出“Yes”,否則輸出“No”,注意,這裡是 x 到達 y ,或者 y 到達 x ,是 或者 不是 而且 !!!
如果是“而且”的話,很明顯的是判斷整個圖是否為一個強連通分量(例如
HDU1269 迷宮城堡,該題的解題報告),那麼就簡單的多了,但是這個題不行。
處理方法(來自 LC 以及 POJ 的discuss):先用強連通縮點來化簡圖,然後在圖上做拓撲排序,如果排序過程中,出現1個以上的點入度同時為0時,那麼就不滿足條件。
tarjan演算法實現:
#include<cstdio>#include<cstring>#include<stack>using namespace std;const int N = 1001;struct Edge{int s,e,next;}edge1[6*N],edge2[6*N];int n,m,e_num1,e_num2,vis_num,cnt;int head[N],instack[N],low[N],tim[N],belong[N],de[N];void AddEdge(int a,int b,Edge edge[],int &e_num){edge[e_num].s=a; edge[e_num].e=b; edge[e_num].next=head[a]; head[a]=e_num++;}void getmap(){int a,b;scanf("%d%d",&n,&m);e_num1=0;memset(head,-1,sizeof(head));while(m--){scanf("%d%d",&a,&b);AddEdge(a,b,edge1,e_num1);}}stack <int> st;void tarjan(int x){int j;tim[x]=low[x]=++vis_num;instack[x]=1;st.push(x);for(j=head[x];j!=-1;j=edge1[j].next){int u=edge1[j].e;if(tim[u]==-1){tarjan(u);if(low[x]>low[u])low[x]=low[u];}else if(instack[u] && low[x]>tim[u])low[x]=tim[u];}if(low[x]==tim[x]){cnt++;do{j=st.top();st.pop();instack[j]=0;belong[j]=cnt;}while(j!=x);}}int topo(){int i,cur,u,count,num;count=0;for(i=1;i<=cnt;i++){if(de[i]==0){cur=i;count++;}}if(count>1)return 0;num=cnt;while(num--){count=0;for(i=head[cur];i!=-1;i=edge2[i].next){u=edge2[i].e;de[u]--;if(de[u]==0){count++;cur=u;}}if(count>1)return 0;}return 1;}void solve(){int i;cnt=vis_num=0;memset(instack,0,sizeof(instack));memset(low,0,sizeof(low));memset(tim,-1,sizeof(tim));for(i=1;i<=n;i++){if(tim[i]==-1)tarjan(i);}e_num2=0;memset(head,-1,sizeof(head));memset(de,0,sizeof(de));for(i=0;i<e_num1;i++){int j=edge1[i].s;int k=edge1[i].e;if(belong[j]!=belong[k]){AddEdge(belong[j],belong[k],edge2,e_num2);de[belong[k]]++;}}topo()==1?puts("Yes"):puts("No");}int main(){int t;scanf("%d",&t);while(t--){getmap();solve();}return 0;}