P4306 [JSOI2010]连通数
Posted hahaha2124652975
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4306 [JSOI2010]连通数相关的知识,希望对你有一定的参考价值。
本题tj区一片大佬各种玄学算法,以至于我根本就没有办法去找代码对拍并让其不超时。。。
那么我的做法是先tarjan求强连通分量并缩点,同时记录此点中共包含了原图的多少点,及多少个点构成了强连通分量并缩成了该点,然后便利缩点后的图,运用记忆化记录该点是否被访问过,可以略微减少一点时间,但是仍有一个点1281ms超时,so等我有能力写出别的代码A掉这道题再来刷掉这道博客嘤嘤嘤
1 #include<set> 2 #include<map> 3 #include<list> 4 #include<queue> 5 #include<stack> 6 #include<string> 7 #include<cmath> 8 #include<ctime> 9 #include<vector> 10 #include<bitset> 11 #include<memory> 12 #include<utility> 13 #include<cstdio> 14 #include<sstream> 15 #include<iostream> 16 #include<cstdlib> 17 #include<cstring> 18 #include<algorithm> 19 using namespace std; 20 const int N=2005; 21 22 stack <int> q; 23 int n,tot,t,num,ans; 24 int head[N],next[N],to[N],dfn[N],low[N],f[N],head2[N],next2[N],to2[N],cou[N]; 25 bool ok[N],visit[N]; 26 27 int mi(int a,int b)return a<b?a:b; 28 int ma(int a,int b)return a>b?a:b; 29 30 void add(int u,int v)//建图 31 next[++tot]=head[u]; 32 head[u]=tot; 33 to[tot]=v; 34 35 36 void add2(int u,int v)//缩点后建图 37 next2[++tot]=head2[u]; 38 head2[u]=tot; 39 to2[tot]=v; 40 41 42 void tarjan(int u)//tarjan模板 43 dfn[u]=low[u]=++t; 44 visit[u]=1; 45 q.push(u); 46 for(int i=head[u];i;i=next[i]) 47 if(!dfn[to[i]]&&ok[to[i]]) 48 tarjan(to[i]); 49 low[u]=mi(low[u],low[to[i]]); 50 51 else if(visit[to[i]]) 52 low[u]=mi(low[u],dfn[to[i]]); 53 54 55 if(dfn[u]==low[u]) 56 int v,l=0; 57 num++; 58 do 59 v=q.top(); 60 q.pop(); 61 visit[v]=0; 62 f[v]=num; 63 l++; 64 while(v!=u); 65 cou[num]=l; 66 67 68 69 int mmp(int u)//递归求每个点的连通数 70 ok[u]=1; 71 for(int i=head2[u];i;i=next2[u]) 72 if(!ok[to2[i]])//该点没有求过 73 cou[u]+=mmp(to2[i]); 74 75 else//若以求过,则直接调用变量 76 cou[u]+=cou[to2[i]]; 77 78 79 return cou[u]; 80 81 82 int main() 83 scanf("%d",&n); 84 for(int i=1;i<=n;i++)//读入 85 char zy[N]; 86 cin>>zy+1; 87 for(int j=1;j<=n;j++) 88 if(zy[j]==‘1‘) 89 add(i,j); 90 ok[i]=ok[j]=true; 91 92 93 94 for(int i=1;i<=n;i++)//遍历原图,缩点 95 if(!dfn[i]&&ok[i]) 96 tarjan(i); 97 98 99 tot=0; 100 for(int i=1;i<=n;i++)//对缩点后的图建图 101 if(ok[i]) 102 for(int j=head[i];j;j=next[j]) 103 if(f[i]!=f[to[j]]) 104 add2(f[i],f[to[j]]); 105 106 107 108 109 memset(ok,0,sizeof(ok)); 110 for(int i=1;i<=num;i++) 111 int k=cou[i];//记录下该强连通分量中有多少个点,因为其可以互相达到对方,故这些点的连通数是一样的 112 ans+=k*mmp(i); 113 //printf("%d\n",ans); 114 115 printf("%d\n",ans);//输出答案 116 return 0; 117
再次申明,这段程序不能A掉着题,仅是提供一种思路(同时水一篇博客嘤嘤嘤),会在最后一个点超时
以上是关于P4306 [JSOI2010]连通数的主要内容,如果未能解决你的问题,请参考以下文章