P2863 [USACO06JAN]牛的舞会The Cow Prom
这题确实是一个近乎(就是)tarjan板子的一道题,也是少有不用缩点的题目
把题目翻译一下吧,就是说若一头奶牛身上的绳子以顺时针方向出去,一直遍历下去可以回来,就说明能够完成圆舞,及若一群奶牛在同一强连通分量中,则可以完成圆舞,而又因为只能顺时针访问,故有向(我之前当成无向图做居然能拿90分??)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<stack> 7 using namespace std; 8 const int M=500005; 9 10 stack < int > q; 11 int n,m,tot,t,ans; 12 int head[M],next[M],to[M],dfn[M],low[M],num[M]; 13 bool ok[M]; 14 15 int mi(int a,int b){return a<b?a:b;} 16 17 int read(){//快读 18 int x=0,w=1; 19 char ch=getchar(); 20 while(ch>'9'||ch<'0'){ 21 if(ch=='-'){ 22 w=-1; 23 } 24 ch=getchar(); 25 } 26 while(ch<='9'&&ch>='0'){ 27 x=(x<<3)+(x<<1)+ch-'0'; 28 ch=getchar(); 29 } 30 return x*w; 31 } 32 33 void add(int u,int v){//链式前向星,构造一条由u指向v的有向边 34 tot++; 35 next[tot]=head[u]; 36 head[u]=tot; 37 to[tot]=v; 38 } 39 40 void tarjan(int g){//tarjan板子 41 dfn[g]=low[g]=++t; 42 ok[g]=1; 43 q.push(g); 44 for(int i=head[g];i;i=next[i]){ 45 if(!dfn[to[i]]){ 46 tarjan(to[i]); 47 low[g]=mi(low[g],low[to[i]]); 48 } 49 else if(ok[to[i]]){ 50 low[g]=mi(low[g],low[to[i]]); 51 } 52 } 53 if(dfn[g]==low[g]){ 54 int l=0; 55 while(q.top()!=g&&!q.empty()){ 56 l++; 57 ok[q.top()]=0; 58 q.pop(); 59 } 60 l++;//emm这里可以用do-while做,之前没想起来。。 61 ok[q.top()]=0; 62 q.pop(); 63 ans+=(l>1);//我们需要考虑单独一个点自成强连通分量的情况 64 } 65 } 66 67 int main(){ 68 n=read(); 69 m=read(); 70 while(m--){ 71 int u,v; 72 u=read(); 73 v=read(); 74 add(u,v);//有向图,由u指向v的一条有向边 75 //add(v,u); 76 } 77 for(int i=1;i<=n;i++){ 78 if(!dfn[i]){ 79 tarjan(i); 80 } 81 } 82 printf("%d\n",ans); 83 return 0; 84 }
嗯白白