BZOJ 1512 [POI2006]Pro-Professor Szu Tarjan缩点+拓扑DP
来源:互联网 发布:php 生成订单号 编辑:程序博客网 时间:2024/05/18 20:46
题意:
n个别墅以及一个主建筑楼,从每个别墅都有很多种不同方式走到主建筑楼,其中不同的定义是(每条边可以走多次,如果走边的顺序有一条不同即称两方式不同)。
询问最多的不同方式是多少,以及有多少个别墅有这么多方式,按照顺序输出别墅编号。
如果最多不同方式超过了36500那么都视作zawsze
解析:
容易想到把边反向,问题转化成求从主建筑楼走向各个点的方案数。
对于一个强连通分量,显然我们可以看做是一个点,所以首先把图缩点。
缩点之后
我们设
显然
并且特别注意的是,初始时,f[belong[主建筑]]=1。
其次任意一个对于任意一个siz[i]>1的点来说,如果f[i]>0的话,那么显然有无数种走法,直接设为maxn+1。
然后我们观察这其实就是个拓扑图上做DP的过程。
直接拓扑图上DP。
最后扫一遍统计解即可。
复杂度:O(常数*n);
代码:
#include <queue>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 1000100#define maxn 36500using namespace std;int n,m,rev_cnt;int rev_head[N];struct Line{ int x,y;}l[N];struct node{ int from,to,next;}rev_edge[N];void init(){ memset(rev_head,-1,sizeof(rev_head)); rev_cnt=1;}void edgeadd(int from,int to,node *edge,int *head,int &cnt){ edge[cnt].from=from,edge[cnt].to=to,edge[cnt].next=head[from]; head[from]=cnt++;}int deep[N],low[N],sta[N],ins[N],belong[N],top,cnt_block,tot;void tarjan(int now){ deep[now]=low[now]=++tot; sta[++top]=now,ins[now]=1; for(int i=rev_head[now];i!=-1;i=rev_edge[i].next) { int to=rev_edge[i].to; if(!deep[to]) { tarjan(to); low[now]=min(low[now],low[to]); }else if(ins[to])low[now]=min(low[now],deep[to]); } if(deep[now]==low[now]) { cnt_block++; int t=-1; do { t=sta[top--]; ins[t]=0; belong[t]=cnt_block; }while(t!=now); }}bool tag[N];int in[N];void re_build(){ for(int i=1;i<=m;i++) { int x=l[i].x,y=l[i].y; if(belong[x]==belong[y]){tag[belong[x]]=1;continue;} edgeadd(belong[x],belong[y],rev_edge,rev_head,rev_cnt); in[belong[y]]++; }}int f[N];void Topsort(){ queue<int>q; for(int i=1;i<=cnt_block;i++) if(!in[i])q.push(i); f[belong[n]]=1; if(tag[belong[n]])f[belong[n]]+=maxn; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=rev_head[u];i!=-1;i=rev_edge[i].next) { int to=rev_edge[i].to; f[to]+=f[u]; if(f[to]>maxn)f[to]=maxn+1; in[to]--; if(!in[to]) { if(tag[to]&&f[to]>0)f[to]=maxn+1; q.push(to); } } }}void calc(){ int ans=-1;top=0; for(int i=1;i<n;i++) if(f[belong[i]]>ans) ans=f[belong[i]]; for(int i=1;i<n;i++) if(f[belong[i]]==ans) sta[++top]=i; printf(ans==maxn+1?"zawsze\n":"%d\n",ans); printf("%d\n",top); for(int i=1;i<=top;i++) printf("%d ",sta[i]); puts("");}int main(){ #ifndef ONLINE_JUDGE freopen("1512.in","r",stdin); freopen("1512.out","w",stdout); #endif init(); scanf("%d%d",&n,&m);n++; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); swap(x,y); edgeadd(x,y,rev_edge,rev_head,rev_cnt); l[i].x=x,l[i].y=y; } for(int i=1;i<=n;i++) if(!deep[i])tarjan(i); init(); re_build(); Topsort(); calc(); #ifndef ONLINE_JUDGE fclose(stdin);fclose(stdout); #endif return 0;}
1 0
- BZOJ 1512 [POI2006]Pro-Professor Szu Tarjan缩点+拓扑DP
- bzoj 1512 [POI2006]Pro-Professor Szu tarjan dp
- 【BZOJ】1512 [POI2006]Pro-Professor Szu 强联通分量+拓扑
- BZOJ 1512 [POI2006]Pro-Professor Szu Tarjan强连通分量 DP
- bzoj1512: [POI2006]Pro-Professor Szu
- [BZOJ 1093 && YZOI1172] Tarjan缩点+拓扑DP 最大半连通子图
- BZOJ 1924 [Sdoi2010]所驼门王的宝藏 tarjan缩点+拓扑DP
- [BZOJ]1093: [ZJOI2007]最大半连通子图 Tarjan缩点+拓扑图DP
- poj 3160【tarjan缩点+拓扑排序+DP】
- [Tarjan缩点 拓扑序DP] SRM 499 1000pts
- BZOJ 2427: [HAOI2010]软件安装 Tarjan缩点 + DP
- BZOJ 1442: [Poi2006]Crystal dp
- BZOJ 2206 缩圈+拓扑[tarjan模板]
- bzoj 2707: [SDOI2012]走迷宫 (高斯消元+概率期望+tarjan缩点+拓扑序)
- BZOJ 1093 浅谈tarjan缩点DAG最长路径即拓扑排序
- BZOJ 1093 最大半连通子图(tarjan缩点 拓扑排序)
- bzoj1924 [Sdoi2010]所驼门王的宝藏(tarjan缩点+拓扑排序+dp)
- CF894E Ralph and Mushrooms(tarjan缩点+拓扑序dp+数学)
- PHP的语言结构和函数的区别
- 在linux下用源代码编译MPICH 3.1.4
- IOS开发笔记-01按钮操作-13.上下左右移动 14.代码优化
- 数据挖掘工程师笔试及答案整理
- c语言之 switch 和 if 的使用比较(一)
- BZOJ 1512 [POI2006]Pro-Professor Szu Tarjan缩点+拓扑DP
- BZOJ 1514 _ [POI2006]ZAB-Frogs 单调队列+二分BFS
- BZOJ 1516 [POI2006]Mag-Warehouse 切比雪夫距离转曼哈顿距离
- 文本挖掘
- Java - socket双向通信例子
- Java-Socket通信 同时JSON传递与解析
- K-means
- linux由浅入深(10.1 )-- shell中的变量
- Java 开发 2.0: NoSQL