2208: [Jsoi2010]连通数

2208: [Jsoi2010]连通数

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1371  Solved: 557
[Submit][Status]

Description

Input

输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。

Output

输出一行一个整数,表示该图的连通数。

Sample Input

3
010
001
100

Sample Output

9

HINT

对于100%的数据,N不超过2000。

Source

第一轮

题解:首先缩点,然后按照惯例重新构图,然后居然每个点都跑一边DFS求联通个数就AC了???(HansBug:逗我?! wnjxyk:QAQ)然后上网刷题解才发现应该是tarjan重构图+拓排+状压DP。。。

  1 {$M 1000000000,0,maxlongint} //为了保险加了个这个^_^,唉Pascal里面栈空间是硬伤啊TT
  2 type
  3     point=^node;
  4     node=record
  5                g:longint;
  6                next:point;
  7     end;
  8     map=array[0..10000] of point;
  9 var
 10    i,j,k,l,m,n,h,t,ans:longint;
 11    a,c:map;
 12    d,e,g,b,f,low,dfn:array[0..100000] of longint;
 13    ss,s:array[0..100000] of boolean;
 14    p:point;
 15    c1:char;
 16 procedure add(var a:map;x,y:longint);
 17           var p:point;
 18           begin
 19                new(p);p^.g:=y;
 20                p^.next:=a[x];a[x]:=p;
 21           end;
 22 function min(x,y:longint):longint;
 23          begin
 24               if x<y then min:=x else min:=y;
 25          end;
 26 procedure tarjan(x:longint);
 27           var p:point;
 28           begin
 29                inc(h);low[x]:=h;dfn[x]:=h;
 30                inc(t);f[t]:=x;
 31                ss[x]:=true;s[x]:=true;
 32                p:=a[x];
 33                while p<>nil do
 34                      begin
 35                           if not(s[p^.g]) then
 36                              begin
 37                                   tarjan(p^.g);
 38                                   low[x]:=min(low[x],low[p^.g]);
 39                              end
 40                           else if ss[p^.g] then low[x]:=min(low[x],dfn[p^.g]);
 41                           p:=p^.next;
 42                      end;
 43                if low[x]=dfn[x] then
 44                   begin
 45                        inc(ans);
 46                        while f[t+1]<>x do
 47                              begin
 48                                   b[f[t]]:=ans;
 49                                   ss[f[t]]:=false;
 50                                   dec(t);
 51                              end;
 52                   end;
 53           end;
 54 procedure dfs(x:longint);
 55           var p:point;
 56          begin
 57               p:=c[x];
 58               f[x]:=i;
 59               inc(m,d[x]);
 60               while p<>nil do
 61                     begin
 62                          if f[p^.g]<>i then dfs(p^.g);
 63                          p:=p^.next;
 64                     end;
 65          end;
 66
 67 begin
 68      readln(n);
 69      for i:=1 to n do a[i]:=nil;
 70      for i:=1 to n do
 71          begin
 72               for j:=1 to n do
 73                   begin
 74                        read(c1);
 75                        if c1=‘1‘ then add(a,i,j);
 76                   end;
 77               readln;
 78          end;
 79      fillchar(b,sizeof(b),0);
 80      fillchar(f,sizeof(f),0);
 81      fillchar(s,sizeof(s),false);
 82      fillchar(ss,sizeof(ss),false);
 83      fillchar(low,sizeof(low),0);
 84      fillchar(dfn,sizeof(dfn),0);
 85      h:=0;t:=0;ans:=0;
 86      for i:=1 to n do if b[i]=0 then tarjan(i);
 87      fillchar(f,sizeof(f),0);
 88      fillchar(d,sizeof(d),0);
 89      fillchar(e,sizeof(e),0);
 90      for i:=1 to n do inc(d[b[i]]);
 91      for i:=1 to ans do c[i]:=nil;
 92      for i:=1 to n do
 93          begin
 94               p:=a[i];
 95               while p<>nil do
 96                     begin
 97                          if b[i]<>b[p^.g] then
 98                             begin
 99                                  inc(e[b[p^.g]]);
100                                  add(c,b[i],b[p^.g]);
101                             end;
102                          p:=p^.next;
103                     end;
104          end;
105      fillchar(f,sizeof(f),0);
106      n:=0;
107      for i:=1 to ans do
108          begin
109               m:=0;dfs(i);
110               n:=n+d[i]*m;
111          end;
112      writeln(n);
113      readln;
114 end.
115        

接下来引用神犇们的正解

题目大意:给定一个n个点的有向图,求有多少点对(x,y),使x沿边可到达y

设f[i][j]为从i到j是否可达

首先强联通分量中的任意两个点均可达 于是我们利用Tarjan缩点

缩点之后是一个拓扑图,我们求出拓扑序,沿着拓扑序从后向前DP,状态转移方程为:

f[i][k]=or{ f[j][k] } (i有直连边到达j,1<=k<=n,n为强连通分量的个数)

鉴于每个点的值只会是1或者0,所以我们可以直接状压,或者干脆开bitset,整体取或即可

时间复杂度O(mn/32)

今天各种手滑。。。Tarjan不赋值dpt和low,拓扑序求出来不用,各种调用错数组。。。终于彻底脑残了好开心233 QAQ

#include<bitset> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 2014 using namespace std; int n,ans,map[M][M],topo_map[M][M]; int dpt[M],low[M],v[M],cnt,belong[M],siz[M],_n,stack[M],top; int into[M],q[M],r,h; bitset<M>f[M]; void Tarjan(int x) { int y; dpt[x]=low[x]=++cnt; stack[++top]=x; for(y=1;y<=n;y++) if(map[x][y]) { if(v[y]) continue; if(dpt[y]) low[x]=min(low[x],dpt[y]); else Tarjan(y),low[x]=min(low[x],low[y]); } if(dpt[x]==low[x]) { int t; ++_n; do{ t=stack[top--]; belong[t]=_n; v[t]=1; ++siz[_n]; }while(t!=x); } } void Topology_Sort() { int i,y; for(i=1;i<=_n;i++) if(!into[i]) q[++r]=i; while(r!=h) { int x=q[++h]; for(y=1;y<=_n;y++) if(topo_map[x][y]) { into[y]--; if(!into[y]) q[++r]=y; } } } int main() { int i,j,x; cin>>n; for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%1d",&map[i][j]); for(i=1;i<=n;i++) if(!v[i]) Tarjan(i); for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(map[i][j]&&belong[i]!=belong[j]) { if(!topo_map[belong[i]][belong[j]]) into[belong[j]]++; topo_map[belong[i]][belong[j]]=1; f[belong[i]][belong[j]]=1; } for(i=1;i<=_n;i++) f[i][i]=1; Topology_Sort(); for(i=_n;i;i--) { x=q[i]; for(j=1;j<=_n;j++) if(topo_map[x][j]) f[x]|=f[j]; } for(i=1;i<=_n;i++) for(j=1;j<=_n;j++) if(f[i][j]) ans+=siz[i]*siz[j]; cout<<ans<<endl; }

时间: 2024-10-29 19:09:40

2208: [Jsoi2010]连通数的相关文章

2208: [Jsoi2010]连通数 - BZOJ

Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图的连通数. Sample Input 3 010 001 100 Sample Output 9HINT 对于100%的数据,N不超过2000. 看到这题然后马上打了一个tarjan 然后对每一个强连通分量dfs,A了之后感觉有点奇怪,这个复杂度是多少来着,我好像算不出来,果断百度题解 然后大囧..

BZOJ 2208: [Jsoi2010]连通数( DFS )

n只有2000,直接DFS就可以过了... -------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cctype> #define rep( i, n ) for( int i = 0; i

bzoj 2208: [Jsoi2010]连通数

一看就是缩点拓扑啊,可数据范围这么小,暴力即可啊. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 #include<vector> 9 #define M 1000009 10 #

【BZOJ】2208 [Jsoi2010]连通数

[算法]强连通分量(tarjan)+拓扑排序+状态压缩(bitset) [题解] 1.强连通分量(scc)内所有点可互达,对答案的贡献为cnt[i]*cnt[i](cnt[i]第i个scc内点的个数),在第四步顺便计算即可,不用单独计算. 2.缩点得到新图,对新图中的每一个点开一个bitset[2000]来记录第i个点能否到达它,初始值为f[i][i]=1. bitset用法:http://blog.163.com/lixiangqiu_9202/blog/static/535750372012

BZOJ 2208 JSOI2010 连通数 Tarjan+拓扑排序

题目大意:给定一个n个点的有向图,求有多少点对(x,y),使x沿边可到达y 设f[i][j]为从i到j是否可达 首先强联通分量中的任意两个点均可达 于是我们利用Tarjan缩点 缩点之后是一个拓扑图,我们求出拓扑序,沿着拓扑序从后向前DP,状态转移方程为: f[i][k]=or{ f[j][k] } (i有直连边到达j,1<=k<=n,n为强连通分量的个数) 鉴于每个点的值只会是1或者0,所以我们可以直接状压,或者干脆开bitset,整体取或即可 时间复杂度O(mn/32) 今天各种手滑...

【BZOJ 2208】 [Jsoi2010]连通数

2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 1431  Solved: 585 [Submit][Status][Discuss] Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图的连通数. Sample Input 3 010 001 100 Samp

bzoj2208:[Jsoi2010]连通数

http://blog.csdn.net/u013598409/article/details/47037499 里面似乎有生成数据的... //我本来的想法是tarjan缩点之后然后将图遍历一遍就可以了,复杂度应该是O(n2)的,为什么说这样是n3的啊... //=>这种做法是错的因为有可能会重复计算用一下传递闭包就可以了然而直接递推以前写的dfsqaq #include<cstdio> #include<cstring> #include<cctype> #i

【bzoj2208】[Jsoi2010]连通数

2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2305  Solved: 989[Submit][Status][Discuss] Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图的连通数. Sample Input 3 010 001 100 Sample

P4306 [JSOI2010]连通数

题面 本题tj区一片大佬各种玄学算法,以至于我根本就没有办法去找代码对拍并让其不超时... 那么我的做法是先tarjan求强连通分量并缩点,同时记录此点中共包含了原图的多少点,及多少个点构成了强连通分量并缩成了该点,然后便利缩点后的图,运用记忆化记录该点是否被访问过,可以略微减少一点时间,但是仍有一个点1281ms超时,so等我有能力写出别的代码A掉这道题再来刷掉这道博客嘤嘤嘤 1 #include<set> 2 #include<map> 3 #include<list&g