比特镇步行(Walk)【虚点+bfs+dfs】
Online Judge:NOIP2016十连测第一场 T3
Label:虚点,bfs,dfs
题目描述
说明/提示
对于100%数据,\(n<=200000\),\(m<=300000\),\(val_i<=2^{20}\)
题解
既然是二进制,只有当\(val_j\)是\(val_i\)的子集时,i有一条连向j的边。
1.先来看看如果只有原图,也就是不考虑两两连边时怎么得到每个点离源点1的距离?
很明显跑个最短路。但由于边权都为1,就不用跑\(dijkstra/spfa\)什么的了,直接一遍\(O(N)\)的\(bfs\)就可以了。
2.考虑两两连边时怎么做?
如果直接两两判断能否连边是\(O(N^2)\),时间和空间都承受不了。
考虑设置虚点,也就是将边\(u->v\),转化为\(u->val_u->...->val_v->v\)。先别在意上面这些边的方向。基本思想就是利用这些二进制数作为中间媒介来模拟连边,根据\(val_i\)的数据范围,顶多只有\(2^{20}=1048576\)个数字,这看起来似乎比较可做。
令\(dis[]\)表示每个点离源点1的距离,由于虚点相当于媒介,我们并不将其计入距离中,所以数组大小开\((N)\)。初始时将\(dis[]\)初始化为-1,源点\(dis[1]=0\)。
设现在\(bfs\)的队首元素为\(x\)。
按照原来的思路,设\(x\)两两连边时能连向实点\(y\)(\(val_j∈val_i\)),如果之前没有访问过\(y\)(也就是\(dis[y]==-1\))则\(dis[y]=dis[x]+1\)。按照bfs的流程走,还应该将\(y\)加进队列末去。所以如何去在可行的时间内去模拟呢?直接套一个\(dfs\),去暴力枚举\(val_x\)的子集,当然如果真的这样做每次取出队首后,时间复杂度都是\(O(val_x的子集数)\),一定会T。回到刚才采取\(bfs\)来搜最短路的思路,如果某个点第一次被访问到,那当前这个准备更新的距离就是他到源点的最短路,所以直接记忆化一下,只有当当前二进制数没有被\(mark\)时才继续dfs子集。
这样每个二进制数最多只会被弄到一次。总的时间复杂度大致为\(O(2^{20}+N+M)\)。
完整代码如下:
ps:下面代码中用\(e\)存实点与实点之间的原有有向边,用\(g\)存\(val_i\)指向\(i\)的有向边。
#include<bits/stdc++.h>
using namespace std;
const int N=200010,M=300010;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
struct Edge{
int to,nxt;
}e[M];//实点与实点
vector<int>g[1<<20];//虚点连向实点
int n,m,head[N],cnt;
inline void link(int u,int v){
e[++cnt].to=v,e[cnt].nxt=head[u];
head[u]=cnt;
}
queue<int>q;
int val[N],dis[N],mark[1<<20];
void boom(int now,int s,int lst){//解决子集
if(mark[now])return;
mark[now]=1;
for(int i=0;i<g[now].size();i++){
int y=g[now][i];
if(dis[y]==-1){
dis[y]=dis[s]+1;
q.push(y);
}
}
for(int i=lst+1;i<=20;i++)if((1<<i)&now)boom(now^(1<<i),s,lst+1);
}
void bfs(){
memset(dis,-1,sizeof(dis));
q.push(1);dis[1]=0;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(dis[y]==-1){
dis[y]=dis[x]+1;
q.push(y);
}
}
boom(val[x],x,-1);
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
val[i]=read();
g[val[i]].push_back(i);
}
for(int i=1;i<=m;i++){
int u=read(),v=read();
link(u,v);
}
bfs();
for(int i=1;i<=n;i++)printf("%d\n",dis[i]);
}
比特镇步行(Walk)【虚点+bfs+dfs】的更多相关文章
- POJ 2227 The Wedding Juicer (优先级队列+bfs+dfs)
思路描述来自:http://hi.baidu.com/perfectcai_/item/701f2efa460cedcb0dd1c820也可以参考黑书P89的积水. 题意:Farmer John有一个 ...
- 邻结矩阵的建立和 BFS,DFS;;
邻结矩阵比较简单,, 它的BFS,DFS, 两种遍历也比较简单,一个用队列, 一个用数组即可!!!但是邻接矩阵极其浪费空间,尤其是当它是一个稀疏矩阵的时候!!!-------------------- ...
- Collect More Jewels(hdu1044)(BFS+DFS)
Collect More Jewels Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Othe ...
- Cleaning Robot (bfs+dfs)
Cleaning Robot (bfs+dfs) Here, we want to solve path planning for a mobile robot cleaning a rectangu ...
- 比特镇旅游(Tourist Attractions)【暴力+Bitset 附Bitset用法】
Online Judge:NOIP2016十连测第一场 T2 Label:暴力,Bitset 题目描述 在美丽的比特镇一共有n个景区,编号依次为1到n,它们之间通过若干条双向道路连接. Byteasa ...
- LeetCode:BFS/DFS
BFS/DFS 在树专题和回溯算法中其实已经涉及到了BFS和DFS算法,这里单独提出再进一步学习一下 BFS 广度优先遍历 Breadth-First-Search 这部分的内容也主要是学习了labu ...
- hdu---------(1026)Ignatius and the Princess I(bfs+dfs)
Ignatius and the Princess I Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (J ...
- Winter(bfs&&dfs)
1084 - Winter PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Winter is ...
- 图的基本遍历算法的实现(BFS & DFS)复习
#include <stdio.h> #define INF 32767 typedef struct MGraph{ ]; ][]; int ver_num, edge_num; }MG ...
随机推荐
- java6大原则之单一职责原则,里式替换原则
单一职责原则:一个接口,一个类,一个方法,最好只做一类事,当然,在真实的项目中,一系列因素下,很难做到单一职责原则,但是针对接口是可以做到的,方法和类要尽量做到 里式替换原则:父类出现的地方,换成子类 ...
- [JZOJ3320] 【BOI2013】文本编辑器
题目 题目大意 给你一个文本,要删去其中所有的'e'. 有三种操作: h光标左移. x删除光标上面的字母(光标是横着的). fc跳到后面的第一个字符为'c'的位置. 问操作序列的最短长度. 思考历程 ...
- R语言 数据重塑
R语言数据重塑 R语言中的数据重塑是关于改变数据被组织成行和列的方式. 大多数时间R语言中的数据处理是通过将输入数据作为数据帧来完成的. 很容易从数据帧的行和列中提取数据,但是在某些情况下,我们需要的 ...
- Date()日期转换和简单计算
/** * 判断是否为闰年 * @param year * @return */ public boolean isLeap ( int year ) { if ( (year % 4 == 0 &a ...
- Super OJ 序列计数
题意: 给出序列 a1,a2,--an(0≤ai≤109),求三元组(ai,aj,ak)(1≤i<j<k≤n)满足 ai<aj>ak 的数量. 分析: 开两个\(BIT\),分 ...
- 微软RPC官方教程
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379010(v=vs.85).aspx 注意:原文版本较老,我更新和改变了部分内容 ...
- Pascal 排序算法
Pascal 排序 排序 排序就是将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程.排序问题是一个十分重要的问题,并且排序的方法有很多种: 例子:输入20个数,将它们按照从高到低的次序排 ...
- 使用Maven命令行下载依赖库
这篇文章,不是教大家如何新建maven项目,不是与大家分享Eclipse与Maven整合. 注意:是在命令行下使用Maven下载依赖库. 废话不说,步骤如下: 1.保证电脑上已成功安装了JDK.运行j ...
- 使用CEfSharp之旅(1) 加载网络页面
原文:使用CEfSharp之旅(1) 加载网络页面 版权声明:本文为博主原创文章,未经博主允许不得转载.可点击关注博主 ,不明白的进群191065815 我的群里问 https://blog.csdn ...
- 设置Hadoop+Hbase集群pid文件存储位置
有时候,我们对运行几天或者几个月的hadoop或者hbase集群做停止操作,会发现,停止命令不管用了,为什么呢? 因为基于java开发的程序,想要停止程序,必须通过进程pid来确定,而hadoop和h ...