[BZOJ5109][LOJ #6252][P4061][CodePlus 2017 11月赛]大吉大利,今晚吃鸡!(最短路+拓扑排序+传递闭包+map+bitset(hash+压位))
5109: [CodePlus 2017]大吉大利,晚上吃鸡!
Time Limit: 30 Sec Memory Limit: 1024 MB
Submit: 107 Solved: 57
[Submit][Status][Discuss]Description
最近《绝地求生:大逃杀》风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏。在游戏中,皮皮和毛毛最喜欢做的事情就是堵桥,每每有一个好时机都能收到不少的快递。当然,有些时候并不能堵桥,皮皮和毛毛会选择在其他的必经之路上蹲点。K博士作为一个老年人,外加有心脏病,自然是不能玩这款游戏的,但是这并不能妨碍他对这款游戏进行一些理论分析,比如最近他就对皮皮和毛毛的战士很感兴趣。【题目描述】游戏的地图可以抽象为一张n个点m条无向边的图,节点编号为1到n,每条边具有一个正整数的长度。假定大魔王都会从S点出发到达T点(S和T已知),并且只会走最短路,皮皮和毛毛会在A点和B点埋伏大魔王。为了保证一定能埋伏到大魔王,同时又想留大魔王一条生路,皮皮和毛毛约定A点和B点必须满足:1.大魔王所有可能路径中,必定会经过A点和B点中的任意一点2.大魔王所有可能路径中,不存在一条路径同时经过A点和B点K博士想知道,满足上面两个条件的A,B点对有多少个,交换A,B的顺序算相同的方案Input
第一行输入四个整数n,m,S,T(1≤n≤5×10^4,1≤m≤5×10^4,1≤S,T≤n),含义见题目描述。接下来输入m行,每行输入三个整数u,v,w(1≤u,v≤n,1≤w≤10^9)表示存在一条长度为w的边链接u和v。1≤n≤5×10^4,1≤m≤5×10^4,1≤w≤10^9Output
输出一行表示答案Sample Input
7 7 1 7
1 2 2
2 4 2
4 6 2
6 7 2
1 3 2
3 5 4
5 7 2Sample Output
6
【样例 1 解释】
合法的方案为 < 2, 3 >, < 2, 4 >, < 4, 3 >, < 4, 5 >, < 6, 3 >, < 6, 5 > 。HINT
来自 CodePlus 2017 11 月赛,清华大学计算机科学与技术系学生算法与竞赛协会 荣誉出品。Credit:idea/陈宇 命题/陈宇 验题/邢健开Git Repo:https://git.thusaac.org/publish/CodePlus201711本次比赛的官方网址:cp.thusaac.org感谢腾讯公司对此次比赛的支持。
题目简述
给定一张有边权(边权全为正)的无向图, $n$ 个点 $m$ 条边,给定起点 $S$ 和终点 $T$ ,问有多少对 $A$ 和 $B$ 满足从 $S$ 到 $T$ 的任意最短路一定经过 $A$ 或者 $B$ ,但是不存在某条最短路同时经过 $A$ 和 $B$ 。
解法一
首先是最暴力的解法,枚举任意点对 $A$ 和 $B$ ,然后删掉 $A$ 和 $B$ ,看看最短距离是否会变长,然后查看 $dis(S, A) + dis(A, B) + dis(B, T)$ 是否和 $dis(S, T)$ 相等,其中 $dis(X, Y)$ 表示原图中点 $X$ 到 $Y$ 的最短距离,由此可以判断枚举的 $A$ 和 $B$ 是否是合法的点对。
其中, $dis(X, Y)$ 可以用floyd求解
时间复杂度: $O \left(n3 \right)$
期望得分: $30$
解法二
首先,虽然题目中给定的是无向图,但是实际上我们可以先从 $S$ 出发求一遍最短路,然后问题变成了:“在有向无环图上,求有多少个满足条件的点对 $A,B$ ,满足从 $S$ 到 $T$ 的所有路径一定经过 $A,B$ 其中一点,并且不存在路径同时经过 $A,B$ ”。
求解这到题目的一个关键点在于: 满足条件的点对 $A,B$ 具有特点:从 $S$ 到 $A$ 的方案数 $\times$ 从 $A$ 到 $T$ 的方案数 + 从 $S$ 到 $B$ 的方案数 $\times$ 从 $B$ 到 $T$ 的方案数 $=$ 从 $S$ 到 $T$ 的方案数。
所以在有向无环图上用动态规划求解路径条数,再去掉 $A$ 可以到达 $B$ 或 $B$ 可以到达 $A$ 的情况即可求解这到题目。
PS:方案数可能会爆掉怎么办?可以对方案数求余一个大整数,如果觉得不够的话可以求余两个大整数。
时间复杂度: $O \left(n2+nm \right)$
期望得分: $60$
解法三
在解法二中,定义 $F(X) = $ 从 $S$ 到 $X$ 的方案数 $\times$ 从 $X$ 到 $T$ 的方案数 = 从 $S$ 经过 $X$ 到达 $T$ 的方案数,所以满足条件的点对 $A,B$ 为:
$F(A) + F(B) = F(T)$
$A$ 和 $B$ 不能相互到达
对于条件 $1$ ,我们可以使用数据结构进行优化(使用std::map即可),而对于条件 $2$ ,我们可以使用 bitset 位压 $32$ 或者 $64$ 位进行加速,使得最终时间和空间都能够承受。
时间复杂度: $O\left(n \log{n}+\frac{nm}{w}\right)$,其中 $w$ 是位压的字长。
期望得分: $100$
题解已经说的很清楚了,标算是hash+压位实现,但是考场上没时间写的话,就用map代替hash,用bitset代替压位,当然代价是常数大了好多倍。
这里说一下传递闭包
所谓传递性,可以这样理解:对于一个节点i,如果j能到i,i能到k,那么j就能到k。求传递闭包,就是把图中所有满足这样传递性的节点都弄出来,计算完成后,我们也就知道任意两个节点之间是否相连。
传递闭包的计算过程一般可以用Warshell算法描述:
For 每个节点i Do
For 每个节点j Do
If j能到i Then
For 每个节点k Do
a[j, k] := a[j, k] Or ( a[j, i] And a[ i, k] )
其中a数组为布尔数组,用来描述两个节点是否相连,可以看做一个无权图的邻接矩阵。可以看到,算法过程跟Floyd很相似,三重循环,枚举每个中间节点。只不过传递闭包只需要求出两个节点是否相连,而不用求其间的最短路径长。
上面的方法可以求出任意两个点是否连通,不过点数不多的时候一般我们可以压位或者bitset,然后就成了:
(实际上是lnk[i][e[j].s]但是可以将数组压缩成一维,也就是:)
rep(i,1,n-1) for (int j=1; j<=cnt; j++) lnk[e[j].s]|=lnk[e[j].t];
这样后面的按照题解做就好了。代码还是比较繁琐的。
- #include<map>
- #include<queue>
- #include<bitset>
- #include<cstdio>
- #include<algorithm>
- #define rep(i,l,r) for (int i=l; i<=r; i++)
- typedef long long ll;
- using namespace std;
- const int N=;
- int n,m,u,v,w,cnt,S,T,h[N];
- struct E{ int to,nxt,w; }e[N<<];
- queue<int> Q;
- int vis[N],iT[N]; ll dis[N],rdis[N];
- void add(int x,int y,int z){
- e[++cnt]=(E){y,h[x],z}; h[x]=cnt;
- e[++cnt]=(E){x,h[y],z}; h[y]=cnt;
- }
- void spfa(ll dis[],int S){
- rep(i,,n) dis[i]=1ll<<,vis[i]=;
- Q.push(S); vis[S]=; dis[S]=;
- while (!Q.empty()){
- int x=Q.front(); Q.pop(); vis[x]=;
- for (int i=h[x],k; i; i=e[i].nxt)
- if (dis[k=e[i].to]>dis[x]+e[i].w){
- dis[k]=dis[x]+e[i].w;
- if (!vis[k]) vis[k]=,Q.push(k);
- }
- }
- }
- namespace G{
- int h[N],rh[N],d[N],rd[N],cnt;
- ll f[N],g[N];
- queue<int>Q;
- bitset<N>lnk[N],rlnk[N];
- map<ll,bitset<N> >M;
- struct E{ int s,t,nxt; }e[N<<];
- void add(int x,int y){
- e[++cnt]=(E){x,y,h[x]}; h[x]=cnt; d[y]++;
- e[++cnt]=(E){y,x,rh[y]}; rh[y]=cnt; rd[x]++;
- }
- ll solve(){
- f[S]=; g[T]=; Q.push(S);
- while (!Q.empty()){
- int x=Q.front(); Q.pop();
- for (int i=h[x]; i; i=e[i].nxt){
- f[e[i].t]+=f[x];
- if (!(--d[e[i].t])) Q.push(e[i].t);
- }
- }
- Q.push(T);
- while (!Q.empty()){
- int x=Q.front(); Q.pop();
- for (int i=rh[x]; i; i=e[i].nxt){
- g[e[i].t]+=g[x];
- if (!(--rd[e[i].t])) Q.push(e[i].t);
- }
- }
- rep(i,,n) lnk[i].set(i),rlnk[i].set(i);
- rep(i,,n-) for (int j=; j<=cnt; j+=) lnk[e[j].s]|=lnk[e[j].t];
- rep(i,,n-) for (int j=; j<=cnt; j+=) rlnk[e[j].s]|=rlnk[e[j].t];
- rep(i,,n) M[1ll*f[i]*g[i]].set(i);
- ll res=;
- rep(i,,n){
- if (!M.count(f[T]-f[i]*g[i])) continue;
- res+=(M[f[T]-f[i]*g[i]] & (~lnk[i]) & (~rlnk[i])).count();
- }
- return res>>;
- }
- }
- int main(){
- freopen("bzoj5109.in","r",stdin);
- freopen("bzoj5109.out","w",stdout);
- scanf("%d%d%d%d",&n,&m,&S,&T);
- rep(i,,m) scanf("%d%d%d",&u,&v,&w),add(u,v,w);
- spfa(dis,S); spfa(rdis,T);
- rep(i,,n) if (dis[i]+rdis[i]==dis[T]) iT[i]=;
- rep(x,,n) if (iT[x])
- for (int i=h[x]; i; i=e[i].nxt)
- if (dis[e[i].to]==dis[x]+e[i].w && iT[e[i].to]) G::add(x,e[i].to);
- printf("%lld\n",G::solve());
- return ;
- }
[BZOJ5109][LOJ #6252][P4061][CodePlus 2017 11月赛]大吉大利,今晚吃鸡!(最短路+拓扑排序+传递闭包+map+bitset(hash+压位))的更多相关文章
- [LOJ 6249]「CodePlus 2017 11 月赛」汀博尔
Description 有 n 棵树,初始时每棵树的高度为 H_i,第 i 棵树每月都会长高 A_i.现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不 ...
- [LOJ 6248]「CodePlus 2017 11 月赛」晨跑
Description “无体育,不清华”.“每天锻炼一小时,健康工作五十年,幸福生活一辈子” 在清华,体育运动绝对是同学们生活中不可或缺的一部分.为了响应学校的号召,模范好学生王队长决定坚持晨跑.不 ...
- loj #6250. 「CodePlus 2017 11 月赛」找爸爸
#6250. 「CodePlus 2017 11 月赛」找爸爸 题目描述 小 A 最近一直在找自己的爸爸,用什么办法呢,就是 DNA 比对. 小 A 有一套自己的 DNA 序列比较方法,其最终目标是最 ...
- [CodePlus 2017 11月赛&洛谷P4058]木材 题解(二分答案)
[CodePlus 2017 11月赛&洛谷P4058]木材 Description 有 n棵树,初始时每棵树的高度为 Hi ,第 i棵树每月都会长高 Ai.现在有个木料长度总量为 S的订单, ...
- [CodePlus 2017 11月赛]晨跑 题解(辗转相除法求GCD)
[CodePlus 2017 11月赛]晨跑 Description "无体育,不清华"."每天锻炼一小时,健康工作五十年,幸福生活一辈子".在清华,体育运动绝 ...
- [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞
[LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞 试题描述 到河北省 见斯大林 / 在月光下 你的背影 / 让我们一起跳舞吧 うそだよ~ 河北省怎么可能有 Stalin. ...
- LOJ6252. 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡! 最短路+bitset
题目传送门 https://loj.ac/problem/6252 https://lydsy.com/JudgeOnline/problem.php?id=5109 题解 首先跑最短路,只保留 \( ...
- 「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)
学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2 ...
- 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!(dij+bitset)
从S出发跑dij,从T出发跑dij,顺便最短路计数. 令$F(x)$为$S$到$T$最短路经过$x$的方案数,显然这个是可以用$S$到$x$的方案数乘$T$到$x$的方案数来得到. 然后第一个条件就变 ...
随机推荐
- 【BZOJ】2099: [Usaco2010 Dec]Letter 恐吓信
[题意]给定长度为n和m的两个字符串S和T,要求在字符串S中取出若干段拼成T(可重复取),求最小段数,n,m<=50000. [算法]后缀自动机 || 后缀数组 [题解]对串S建SAM,然后在上 ...
- python笔记之BytesIO
1. 什么是BytesIO BytesIO与StringIO类似,不同的是StringIO只能存放string,BytesIO是用来存放bytes的,它提供了在内存中读写字节的能力. 即在内存中读写字 ...
- 重载jquery on方法实现click事件在移动端的快速响应
额,这个标题取的还真是挺装的... 其实我想表达的是jquery click事件如何在移动端自动转换成touchstart事件. 因为移动端click事件会比touchstart事件慢几拍 移动设备某 ...
- ueditor和thinkphp框架整合修改版
基于tp官网上的一篇文章修改的 因为tp中所有目录其实都是性对于入口文件的 在原来的基础上略做修改后 已经做到 无论项目放在www下的任何位置 图片在编辑器中回填后都能正常显示! http://fi ...
- Coursera在线学习---第四节.过拟合问题
一.解决过拟合问题方法 1)减少特征数量 --人为筛选 --靠模型筛选 2)正则化(Regularization) 原理:可以降低参数Θ的数量级,使一些Θ值变得非常之小.这样的目的既能保证足够的特征变 ...
- 72.xilinx vivado zynq vdma仿真及应用详解(一)
很多人用zynq平台做视频图像开发,但是对vdma了解比较少,上手起来稍微有些困难,我针对这一现象,做了一个基于vivado和modelsim的仿真和应用测试工程,并写篇文章做些介绍,希望能对大家有帮 ...
- linux设备驱动模型-浅析-转
1. typeof typeof并非ISO C的关键字,而是gcc对C的一个扩展.typeof是一个关键字(类似sizeof),用于获取一个表达式的类型. 举个简单的例子: char tt; typ ...
- Spring中的@Transactional事务注解
事务注解方式 @Transactional 当标于类前时, 标示类中所有方法都进行事物处理 , 例子: @Transactional public class TestServiceBean impl ...
- log4j生成日志
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件,甚至是套接口服务器.NT的事件记录器.UNIX Syslog守护进程等:我们也可 ...
- java网络编程三次握手四次挥手
第一次握手:client设置syn=1,随机产生一个序列号seq=x,将数据包发送到server.client进入syn_send状态, 等待server确认. 第二次握手:server查看clien ...