【BZOJ】【2208】【JSOI2010】连通数

题解:

  1.Tarjan缩点以后对每个连通分量进行深搜,看能到哪些连通分量,能到达的所有连通分量的size之和记为sum。则第i个连通分量对答案的贡献为size[i]*sum(到其他连通分量)+size[i]*size[i](本身互相可达)

  2.在网上搜了一下……这题可以直接dfs过……汗。“正解”是Tarjan缩点+拓扑排序+状态压缩

  1 /**************************************************************
  2     Problem: 2208
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:9476 ms
  7     Memory:64772 kb
  8 ****************************************************************/
  9
 10 //BZOJ 2208
 11 #include<vector>
 12 #include<cstdio>
 13 #include<cstdlib>
 14 #include<cstring>
 15 #include<iostream>
 16 #include<algorithm>
 17 #define rep(i,n) for(int i=0;i<n;++i)
 18 #define F(i,j,n) for(int i=j;i<=n;++i)
 19 #define D(i,j,n) for(int i=j;i>=n;--i)
 20 using namespace std;
 21 const int N=2015;
 22 typedef long long LL;
 23 void read(int &v){
 24     v=0; int sign=1; char ch=getchar();
 25     while(ch<‘0‘||ch>‘9‘) {if (ch==‘-‘) sign=-1; ch=getchar();}
 26     while(ch>=‘0‘&&ch<=‘9‘) {v=v*10+ch-‘0‘; ch=getchar();}
 27     v*=sign;
 28 }
 29 /*******************tamplate********************/
 30 int to1[N*N],head1[N],next1[N*N],cnt=0;
 31 int to2[N*N],head2[N],next2[N*N];
 32 void ins1(int x,int y){
 33     to1[++cnt]=y; next1[cnt]=head1[x]; head1[x]=cnt;
 34 }
 35 void ins2(int x,int y){
 36     to2[++cnt]=y; next2[cnt]=head2[x]; head2[x]=cnt;
 37 }
 38 /***********************************************/
 39 int n,m;
 40 int dfn[N],low[N],dfs_clock=0,belong[N],num,size[N];
 41 int st[N],top=0;
 42 bool in[N];
 43 void tarjan(int x){
 44     int y;
 45     dfn[x]=low[x]=++dfs_clock;
 46     st[top++]=x;
 47     in[x]=1;
 48     for(int i=head1[x];i;i=next1[i]){
 49         y=to1[i];
 50         if (!dfn[y]){
 51             tarjan(y);
 52             low[x]=min(low[x],low[y]);
 53         }
 54         else if (in[y]) low[x]=min(low[x],dfn[y]);
 55     }
 56     if (low[x]==dfn[x]){
 57         num++; size[num]=0;
 58         for(y=0;y!=x;){
 59             y=st[--top];
 60             in[y]=0;
 61             belong[y]=num;
 62             size[num]++;
 63         }
 64     }
 65 }
 66 void rebuild(){
 67     cnt=0;
 68     F(x,1,n)
 69         for(int i=head1[x];i;i=next1[i])
 70             if (belong[x]!=belong[to1[i]])
 71                 ins2(belong[x],belong[to1[i]]);
 72 }
 73 /***********************************************/
 74 bool vis[N];
 75 int sum=0;
 76 void dfs(int x){
 77     int y;
 78     for(int i=head2[x];i;i=next2[i]){
 79         y=to2[i];
 80         if (!vis[y]){
 81             vis[y]=1;
 82             sum+=size[y];
 83             dfs(y);
 84         }
 85     }
 86 }
 87 void solve(){
 88     LL ans=0;
 89     F(i,1,num){
 90         memset(vis,0,sizeof vis);
 91         sum=0;
 92         dfs(i);
 93         ans+=size[i]*sum+size[i]*size[i];
 94     }
 95     printf("%lld\n",ans);
 96 }
 97 int main(){
 98     #ifndef ONLINE_JUDGE
 99     freopen("input.txt","r",stdin);
100     #endif
101     read(n);
102     char s[N];
103     F(i,1,n){
104         scanf("%s",s);
105         rep(j,strlen(s))
106             if (s[j]==‘1‘) ins1(i,j+1);
107     }
108     F(i,1,n) if (!dfn[i]) tarjan(i);
109     rebuild();
110     solve();
111     return 0;
112 }

时间: 2024-10-15 22:50:20

【BZOJ】【2208】【JSOI2010】连通数的相关文章

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+拓扑排序

题目大意:给定一个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) 今天各种手滑...

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了之后感觉有点奇怪,这个复杂度是多少来着,我好像算不出来,果断百度题解 然后大囧..

2208: [Jsoi2010]连通数

2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 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

【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]连通数

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

(暴力) bzoj 2208

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

【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