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掉着题,仅是提供一种思路(同时水一篇博客嘤嘤嘤),会在最后一个点超时

posted @ 2019-07-15 12:26  喵呜,颜儿ღ  阅读(173)  评论(0编辑  收藏  举报