博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj 2208】[Jsoi2010]连通数(dfs||Tarjan算法+拓扑序+dp)
阅读量:5224 次
发布时间:2019-06-14

本文共 2955 字,大约阅读时间需要 9 分钟。

2208: [Jsoi2010]连通数

Time Limit: 20 Sec  
Memory Limit: 512 MB
Submit: 2383  
Solved: 1013
[ ][ ][ ]

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||Tarjan算法+拓扑序+dp】

[way 1]【朴素dfs,直接暴力,只是,时间不大科学。我刚开始想像初始化树的方式来搞,但是由于有环,搞成了死循环】

[way 2]【一个比较科学的方法,先用Tarjan将环缩成一个点,然后,重新反向建图,按拓扑序处理,g[i][j]表示从i号点出发,状态为j的情况是否存在。用bitset处理】

dfs卡时A码:

 

#include
#include
#include
using namespace std;int a[4000010],nxt[4000010],p[2010],tot;int n,dis[2010],ans;bool vis[2010];inline void add(int x,int y){ tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot;}void dfs(int x){ dis[x]=1; vis[x]=1; for(int i=p[x];i!=-1;i=nxt[i]) if(!vis[a[i]]) { dfs(a[i]); dis[x]+=dis[a[i]]; }}int main(){ int i,j; memset(p,-1,sizeof(p)); memset(nxt,-1,sizeof(nxt)); scanf("%d\n",&n); for(i=1;i<=n;++i) { char s[2010]; scanf("%s",s+1); for(j=1;j<=n;++j) if(s[j]=='1') add(i,j); } for(i=1;i<=n;++i) { memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); dfs(i); ans+=dis[i]; } printf("%d\n",ans); return 0;}

Tarjan算法+拓扑序+dp:

 

 

#include
#include
#include
#include
#include
using namespace std;bitset<2010>g[2010];queue
que;int a[4000010],nxt[4000010],p[2010],tot;int a1[4000010],Nxt[4000010],point[2010],tt;int dft[2010],dis[2010],size[2010],root,cnt;int d[50010],top,f[2010],in[2010];int n,ans;bool vis[2010],ch[2010][2010];inline void add(int x,int y){ tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot;}inline void Add(int x,int y){ tt++; a1[tt]=y; Nxt[tt]=point[x]; point[x]=tt;}void tarjan(int x){ dis[x]=dft[x]=++cnt; d[++top]=x; vis[x]=1; for(int i=p[x];i!=-1;i=nxt[i]) if(!dft[a[i]]) { tarjan(a[i]); dis[x]=min(dis[x],dis[a[i]]); } else if(vis[a[i]]&&dis[x]>dft[a[i]]) dis[x]=dft[a[i]]; if(dis[x]==dft[x]) { ++root; int b; do{ b=d[top--]; size[root]++; f[b]=root; vis[b]=0; }while(x!=b); } return;}inline void solve(){ for(int i=1;i<=root;++i) g[i][i]=1; for(int i=1;i<=root;++i) if(!in[i]) que.push(i); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=point[u];i!=-1;i=Nxt[i]) { g[a1[i]]|=g[u]; in[a1[i]]--; if(!in[a1[i]]) que.push(a1[i]); } } for(int i=1;i<=root;++i) for(int j=1;j<=root;++j) if(g[i][j]) ans+=size[i]*size[j]; return;}int main(){ int i,j; memset(p,-1,sizeof(p)); memset(nxt,-1,sizeof(nxt)); scanf("%d\n",&n); for(i=1;i<=n;++i) { char s[2010]; scanf("%s",s+1); for(j=1;j<=n;++j) if(s[j]=='1') add(i,j); } for(i=1;i<=n;++i) if(!dft[i]) tarjan(i); memset(Nxt,-1,sizeof(Nxt)); memset(point,-1,sizeof(point)); for(i=1;i<=n;++i) for(j=p[i];j!=-1;j=nxt[j]) if(f[i]!=f[a[j]]&&!ch[f[a[j]]][f[i]]) Add(f[a[j]],f[i]),ch[f[a[j]]][f[i]]=1,in[f[i]]++; solve(); printf("%d\n",ans); return 0;}

 

 

 

转载于:https://www.cnblogs.com/lris-searching/p/9402993.html

你可能感兴趣的文章
python 基础 ----- 变量
查看>>
设计模式课程 设计模式精讲 2-2 UML类图讲解
查看>>
Silverlight 的菜单控件。(不是 Toolkit的)
查看>>
:hover 鼠标同时触发两个元素变化
查看>>
go语言学习十三 - 相等性
查看>>
Idea 提交代码到码云(提交到github也大同小异)
查看>>
c#连接excel2007未安装ISAM解决
查看>>
Mono 异步加载数据更新主线程
查看>>
初识lua
查看>>
我是插件狂人,jDuang,jValidator,jModal,jGallery
查看>>
张季跃 201771010139《面向对象程序设计(java)》第四周学习总结
查看>>
如何解除循环引用
查看>>
android中fragment的使用及与activity之间的通信
查看>>
字典【Tire 模板】
查看>>
jquery的contains方法
查看>>
python3--算法基础:二分查找/折半查找
查看>>
Perl IO:随机读写文件
查看>>
Perl IO:IO重定向
查看>>
转:基于用户投票的排名算法系列
查看>>
WSDL 详解
查看>>