joj 2737 狼与羊的故事 求任意两点之间的必经之路
村长要召开羊族大会,讨论羊族未来的发展,要求羊羊们到指定地点集合。小羊们收到通知后从家里出发到达指定地点。每个羊的家都是与其他羊的家连通的,可以互相访问。 比如说可以从1到3,同样也可以从3到1 。灰太郎听到这个消息后,准备有所行动(你懂的)。但他不知道应该在哪条路上等羊。但他知道,有的路线一定要进过某条边。如上图从1到5一定要经过4-5这条路,这样他可以在那条路上事先埋伏好。现在他想知道2个点之间有多少这样的路。如果没有输出0.
Input
第一行有两个整数N,M。表示有N(1<N<10001)个家,M(1<M<10001)条路线。随后有M行,每行有两个不相同的整数A、B表示 A,B之间有一条路。我们保证任意时刻任意两个地点都能够相互到达并且2点之间最多只有1条路。接下来输入一个数K(K<20001)表示有K次查询。随后有K行。 每行有两个不相同的整数A、B询问 A,B之间有多少条的那样的路。
Output
对于每个询问输出有多少条那样的路。
Sample Input
5 5 1 2 3 4 2 4 3 1 5 4 4 1 5 3 5 2 3 4 1
Sample Output
1 1 0 0
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
//求任意两点之间的必经之路
//求桥边
//缩点
//求LCA
///此题中没有重边
const int maxn=30000;
struct fedge
{
int t,index;
int next;
};
int V,E;
int p[maxn];
fedge G[maxn*2];
int l;
void init()
{
memset(p,-1,sizeof(p));
l=0;
}
void addedge(int u,int t,int index,int l)
{
G[l].t=t;
G[l].index=index;
G[l].next=p[u];
p[u]=l;
}
int isbridge[maxn];
//tarjan 求割点 割边(没有重边)
int cut[maxn];//cut[i]非0表示i是割点
int color[maxn];//颜色:0表示没有访问,1表示正在访问,2表示访问结束
int lowc[maxn];//表示i及i的子孙相连的辈分最高的祖先节点所在的深度
int d[maxn];//表示i节点在树中的深度
int root;//根节点
int fath;//父节点
int pcnt;//割点个数
int egcnt;//割边个数
int egt[maxn];
int egu[maxn];
int egv[maxn];
void dfs(int u,int fath,int deep)
{
color[u]=1;//正在访问
lowc[u]=d[u]=deep;//深度
int tot=0;//子树个数
for(int i=p[u];i!=-1;i=G[i].next)
{
int t=G[i].t,index=G[i].index;
if(t!=fath&&color[t]==1)
{
lowc[u]=min(lowc[u],d[t]);
}
if(color[t]==0)
{
dfs(t,u,deep+1);
tot++;//子树加1
lowc[u]=min(lowc[u],lowc[t]);
//求割点
//if((u==root&&tot>1)||(u!=root&&lowc[t]>=d[u])) cut[u]=1;//不能将pscnt++写到这里
//求割边
if(lowc[t]>d[u]) //edge[u][t]=true; u->t是割边
{
//判断重边
egu[egcnt]=u;
egv[egcnt]=t;
egt[egcnt++]=index;
isbridge[index]=1;
}
}
}
color[u]=2;
}
void calc()
{
pcnt=egcnt=0;
memset(color,0,sizeof(color));
memset(lowc,0,sizeof(lowc));
memset(d,0,sizeof(d));
memset(cut,0,sizeof(cut));
root=1;
dfs(1,-1,1);
//for(int i=1;i<=V;i++) if(cut[i]) pcnt++;
}
//去掉桥边 缩点
int tp[maxn];
fedge tG[maxn*2];
int tl;
void taddedge(int u,int t,int index,int l)
{
tG[l].t=t;
tG[l].index=index;
tG[l].next=tp[u];
tp[u]=l;
}
int vis[maxn];
int belg[maxn];//节点i属于第几块
void find(int u,int id)
{
vis[u]=1;belg[u]=id;
for(int i=p[u];i!=-1;i=G[i].next)
{
int t=G[i].t,index=G[i].index;
if(!isbridge[index]&&!vis[t])
{
find(t,id);
}
}
}
int det;//缩点后节点个数
void rebuildgraph()
{
memset(tp,-1,sizeof(tp));
tl=0;
det=0;
memset(vis,0,sizeof(vis));
memset(belg,0,sizeof(belg));
for(int i=1;i<=V;i++)
{
if(!vis[i])
{
find(i,++det);
}
}
//求LCA中会加上桥边
/*for(int i=0;i<egcnt;i++)//缩点后再加上桥边
{
int u=egu[i],v=egv[i];
int tu=belg[u],tv=belg[v];
taddedge(tu,tv,i+1,tl++);
// taddedge(tv,tu,i+1,tl++);
}*/
}
//RMQ求LCA
const int N = 11005;
const int M = 101;
const int MAX = 10000000;
int n;
struct Edge
{
int u,v,next;
}edge[N*2];
int head[N],tot = 0;
void addedge(int u, int v)
{
tot++;
edge[tot].u = u;
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int first[N];//结点在搜索顺序数组中最先出现的位置(下标)
int occur[2*N];//结点在出现的顺序数组重复的也要记录
int depth[2*N];//结点在搜索树中的深度,与occur相对应
int dp_min[2*N][20];//dp_min[i][j] 表示从第i个位置开始的2^j个元素中的最小值的下标
int m ;//不断记录出现的下标
void rdfs(int u, int deep,int fath)
{
occur[++m] = u;//进入该点时进行记录
depth[m] = deep;
if(!first[u])
{
first[u] = m;
}
for(int i = head[u]; i != 0; i = edge[i].next)
{
if(edge[i].v==fath) continue;
rdfs(edge[i].v, deep+1,u);
occur[++m] = u;//访问子树返回也要标记
depth[m] = deep;
}
}
int lev[maxn];
void calclevel(int u,int fath)
{
for(int i=head[u];i!=0;i=edge[i].next)
{
int t=edge[i].v;
if(t==fath) continue;
lev[t]=lev[u]+1;
calclevel(t,u);
}
}
void rinit()
{
tot = 0;
m = 0;
memset(head,0,sizeof(head));
memset(first,0,sizeof(first));
int u,v;
//cin>>n;
n=det;
/*for(int i = 1; i < n; i++)
{
cin>>u>>v;
addedge(u,v);
in[v] = true;
}*/
for(int i=0;i<egcnt;i++)//建树
{
int u=egu[i],v=egv[i];
int tu=belg[u],tv=belg[v];
addedge(tu,tv);
addedge(tv,tu);
}
lev[1]=0;
calclevel(1,-1);
rdfs(1,1,-1);
}
void rmq_init()
{
for(int i = 1; i <= m; i++)
{
dp_min[i][0] = i;
}
for(int j = 1,s = 1; s <= m; s = (1<<(j++)))
{
for(int i = 1; i+s < m; i++)
{//由于要求的是最小值的下标这里采用间接比较,将长为s的区间分为相等的两端求最小值,以2的幂不断增加s,最终的解
dp_min[i][j] = depth[dp_min[i][j-1]] < depth[dp_min[i+s][j-1]] ? dp_min[i][j-1] : dp_min[i+s][j-1];
}
}
}
int rmq_min(int a, int b)
{
int l=first[a],r=first[b];//得到区间的左右端点
if(l > r)
{
int t = l;
l = r;
r = t;
}
int k = floor(log(double(r-l+1))/log(2.0));
int s = 1<<k;
int min_id = depth[dp_min[l][k]] < depth[dp_min[r-s+1][k]] ? dp_min[l][k] : dp_min[r-s+1][k];
return occur[min_id];
}
int main()
{
while(scanf("%d%d",&V,&E)==2)
{
init();
memset(isbridge,0,sizeof(isbridge));
for(int i=1;i<=E;i++)
{
int u,t,index=i;
scanf("%d%d",&u,&t);
u++,t++;
addedge(u,t,index,l++);
addedge(t,u,index,l++);
}
calc();
//删除桥边 缩点
rebuildgraph();
rinit();
rmq_init();
int q;scanf("%d",&q);
while(q--)
{
int s,t;scanf("%d%d",&s,&t);
s++,t++;
s=belg[s],t=belg[t];//缩点后的图
int la=rmq_min(s,t);
printf("%d\n",lev[s]+lev[t]-lev[la]*2);
}
}
return 0;
}
joj 2737 狼与羊的故事 求任意两点之间的必经之路相关推荐
- JOJ2737:狼与羊的故事(求图上任意两点间的桥边)
2737: 狼与羊的故事 Result TIME Limit MEMORY Limit Run Times AC Times JUDGE 3s 65536K 53 10 Standard 村长要召开 ...
- Dijkstra最短路由算法,求任意两点之间的最短距离【Java】
一.问题 求下图中节点0到节点5之间的最短距离 二.方法 Dijkstra最短路由算法.本文不再赘述,直接上代码,如果不懂,可以参考 文章 三.代码 public class MyDijkstra { ...
- bzoj1412[ZJOI2009]狼和羊的故事
bzoj1412[ZJOI2009]狼和羊的故事 题意: n*m网格,每个格子可能为狼.羊或空格.现在要在一些格子边界篱笆使羊狼分开,求最短篱笆.n,m≤100 题解: 最小割问题,建一个超级源和超级 ...
- [ZJOI2009]狼和羊的故事 题解
狼和羊的故事 怎么说呢,这道题其实不难,只是题意有那么亿点点难理解.我最开始想复杂了,理解为了栅栏长度是格点的周长,那事情就复杂了... 题目分析: 首先,要明确的是:一个狼领地和羊领地之间只需建长度 ...
- BZOJ 1412: [ZJOI2009]狼和羊的故事
1412: [ZJOI2009]狼和羊的故事 >原题链接< Description "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......& ...
- 【BZOJ1412】【ZJOI2009】狼和羊的故事(网络流)
Description "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向--" Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说 ...
- [bzoj1934]: [ZJOI2009]狼和羊的故事
1412: [ZJOI2009]狼和羊的故事 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 3105 Solved: 1567 [Submit][ ...
- 题解 P2598 【[ZJOI2009]狼和羊的故事】
P2598 [ZJOI2009]狼和羊的故事 题目描述 "狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......" Orez听到这首歌,心想:狼 ...
- [ZJOI2009]狼和羊的故事【最小割】
题目链接 P2598 [ZJOI2009]狼和羊的故事 要让羊和狼都区别开来,需要的最小的割是多少?每只羊向四周有4个可能的方向,每只狼也是同样的,所以每个动物向周围可以跑出4个流,我们要建立栅栏,可 ...
最新文章
- Windows驱动开发要点总结一
- Ardino基础教程 21_最简单最快控制LCD1602
- java防止表单二次提交_防止表单重复提交
- java this$0_java中this$0的含义及用法
- 配置maven mvn命令使用jdk 1.7编译
- android 点击外部接收事件,Android Dialog外部点击事件
- android闹钟——原代码【转】
- 循环所有数据库执行脚本
- 网络(13)-SYN flood及其应对方法
- eclipse 安装和使用AmaterasUML
- 智能优化算法:树种算法-附代码
- VIBE算法(一)——论文翻译
- 开发与测试的相爱相杀
- 常用触摸屏485通讯引脚及下载口
- java毕业设计博弈论学习网站Mybatis+系统+数据库+调试部署
- 选择性粘贴HTML,Excel中“选择性粘贴”的五种特殊用法
- UEFI Boot Flow 系列之 SEC Phase
- 北京航空航天大学计算机系考研复试上机真题及答案---2014
- C++程序屏蔽windows2008系统安全界面(ctrl+alt+delete热键)
- git push报错:fatal: unable to access ‘https://XXXX.git/‘: Peer‘s Certificate issuer is not recognized.
热门文章
- python 区间频数统计_pandas分区间,算频率的实例
- 顺序查找以及带哨兵的顺序查找java版本
- Git将远程强制同步到本地
- PostgreSql 认证方式-Peer 认证
- 因为相信所以看见,既然看见注定坚信《16》
- 【学习】 CSS总结
- python入门函数编程_12、Python入门____语法入门(五)函数式编程
- QT打开文件及文件路径
- [esp32 + LVGL]物理按键控制屏幕上开关和LED闪烁
- html实现富文本编辑器,前端程序员福利,6款轻量级富文本编辑器,轻松实现富文本编辑...