标签:pre lan href 强连通分量 ace string show mes include
本题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掉着题,仅是提供一种思路(同时水一篇博客嘤嘤嘤),会在最后一个点超时
标签:pre lan href 强连通分量 ace string show mes include
原文地址:https://www.cnblogs.com/hahaha2124652975/p/11146508.html