拓扑排序复习——Chemist
一、基本算法
拓扑序列:对于一张有向图,求一个序列ai若对于每一条边(u,v),都满足au<=av ,则称这个序列为这张有向图的拓扑序列,一张图可能有多个拓扑序列。
求拓扑序列:找到入度为0的点,加入队列中,每次取出队列顶端的点加入拓扑序列的最后,将它到达的点的入度-1,然后再重复做,直到没有点的入度为0,若最后还是有点的入度大于0,则说明有向图中存在环。
代码:
void add(int x,int y)
{
num++;
in[y]++;
End[num]=y;
Next[num]=Head[x];
Head[x]=num;
}
void topsort()
{
queue<int>q;
for(int i=;i<=n;i++)
if(!in[i])q.push(i);
while(!q.empty())
{
int x=q.front();q.pop();
seq[++cnt]=x;
for(int i=Head[x];i;i=Next[i])
{
int y=End[i];
in[y]--;
if(in[y]==)q.push(y);
}
}
}
二、应用
1.求字典序最小/最大的拓扑序列。
只需将上面代码中的队列换成小根堆/大根堆即可,每次取出堆顶,方法相同。
2.洛谷P1983车站分级
由于存在明显的优先级关系,所以考虑拓扑排序,按照小于的关系连边,然后拓扑排序一遍,找到最大的d[i]就是最少需要分的级别,因为这一段序列中的点必须满足级别严格递减。(再具体的题解可以看cellur的题解)
代码:
#include<bits/stdc++.h>
using namespace std;
const int M=2e6;
int n,m,cnt=,sta[],d[],in[],w[];
bool v[];
int num=,end[M],next[M],head[];
void add(int x,int y)
{
if()puts("AC");
num++;
in[y]++;
end[num]=y;
next[num]=head[x];
head[x]=num;
}
void topsort()
{
queue<int>q;
for(int i=;i<=n+m;i++)
if(!in[i])q.push(i),d[i]=w[i];
while(q.size())
{
int x=q.front();q.pop();
for(int i=head[x];i;i=next[i])
{
int y=end[i];
in[y]--;
d[y]=d[x]+w[y];
if(in[y]==)q.push(y);
}
}
}
int main()
{
cin>>n>>m;
for(int i=;i<=n;i++)
w[i]=;
for(int i=;i<=m;i++)
{
memset(v,,sizeof v);
cin>>cnt;
for(int j=;j<=cnt;j++)
scanf("%d",&sta[j]),v[sta[j]]=;
for(int j=sta[];j<=sta[cnt];j++)
if(!v[j])add(j,n+i);
for(int j=;j<=cnt;j++)
add(n+i,sta[j]);
}
topsort();
int ans=;
for(int i=;i<=n;i++)
ans=max(ans,d[i]);
cout<<ans<<endl;
return ;
}
3.洛谷P3243菜肴
最先想到的就是求出字典序最小的拓扑序列,然而我们很容易举出反例,如两个限制:5>2,4>3,这时的答案显然是1 5 2 4 3,而不是1 4 3 5 2,而后者的字典序小于前者。那么我们不妨换一种思路,在反图中求出字典序最大的序列,然后反着输出,如果遇到环就特判输出Impossible。这样为什么是对的呢?因为求最大的拓扑序的话就是在能放的中选择一个最大的放到最前面,如果不放这个而放次大的能放的,那么反过来之后,这个最大的一定在次大的前面,而本来它是可以放到次大的后面的,所以这样一定是最优的。
至于求字典序最大的拓扑序的方法在前面已经说过,这里用大根堆实现,直接看代码:
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+;
int T,n,m,in[M],seq[M];
int num=,cnt=,Head[M],Next[M],End[M];
void add(int x,int y)
{
num++;
End[num]=y;
Next[num]=Head[x];
Head[x]=num;
}
void clear()
{
cnt=num=;
for(int i=;i<=n;i++)
in[i]=Head[i]=;
for(int i=;i<=m;i++)
Next[i]=End[i]=;
}
bool topsort()
{
priority_queue<int>q;//大根堆
for(int i=n;i>=;i--)
if(!in[i])q.push(i);
while(!q.empty())
{
int x=q.top();q.pop();
seq[++cnt]=x;
for(int i=Head[x];i;i=Next[i])
{
int y=End[i];
in[y]--;
if(in[y]==)q.push(y);
}
}
for(int i=;i<=n;i++)
if(in[i]>)return ;
return ;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
clear();
for(int i=;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(y,x);
in[x]++;
}
if(!topsort())puts("Impossible!");
else{
for(int i=n;i>=;i--)
printf("%d ",seq[i]);
puts("");
}
}
return ;
}
4.HDU5222 Exploration
题意:给你一张混合图(既有有向边又有无向边),问有没有简单环。
先将无向边连接的点通过并查集合并成一个点,同时判断是否只通过无向边就能形成环,然后再加入有向边,注意添加的边的起始点为起始点所在集合编号,终点为终点所在集合编号,同时也要判断添加的起始点是否已经属于同一个集合,然后拓扑排序一遍,判断缩点后的有向图是否存在环,当然也可以用Tarjan做。注意多组数据一定要每次把邻接表也清零,因为这个WA了好多次。。。
代码:
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int M=1e6+;
int T,n,m1,m2;
int fa[M],in[M];
int num=,Head[M],Next[M],End[M];
int get(int x)
{
if(x==fa[x])return x;
else return fa[x]=get(fa[x]);
}
void Union(int x,int y)
{
fa[get(x)]=get(y);
}
void add(int x,int y)
{
num++;
End[num]=y;
Next[num]=Head[x];
Head[x]=num;
}
void clear()
{
num=;
for(int i=;i<=n;i++)
fa[i]=i,in[i]=,Head[i]=;
for(int i=;i<=m2;i++)
End[i]=Next[i]=;
}
bool topsort()
{
queue<int>q;
for(int i=;i<=n;i++)
if(fa[i]==i&&in[i]==)q.push(i);
while(q.size())
{
int x=q.front();q.pop();
for(int i=Head[x];i;i=Next[i])
{
int y=End[i];
in[y]--;
if(in[y]==)q.push(y);
}
}
for(int i=;i<=n;i++)
if(fa[i]==i&&in[i]>)return ;
return ;
}
int main()
{
scanf("%d",&T);
while(T--)
{
bool flag=;
int x,y;
scanf("%d%d%d",&n,&m1,&m2);
clear();
for(int i=;i<=m1;i++)//加无向边
{
scanf("%d%d",&x,&y);
if(get(x)==get(y))flag=;
//如果无向边就能构成环
else Union(x,y);
}
for(int i=;i<=m2;i++)
{
scanf("%d%d",&x,&y);
int fx=get(x),fy=get(y);
if(fx==fy)flag=;
add(fx,fy);
in[fy]++;
}
if(flag)puts("YES");
else{
bool f=topsort();
if(f)puts("YES");
else puts("NO");
}
}
return ;
}
拓扑排序复习——Chemist的更多相关文章
- 《数据结构与算法分析:C语言描述》复习——第九章“图论”——拓扑排序
2014.07.04 17:23 简介: 我们考虑一种特殊的图: 1. 有向图 2. 只有一个连通分量 3. 不存在环 那么这样的图里,必然可以找到一种排序方式,来确定谁在谁的“前面”. 简单的来说可 ...
- noip复习之拓扑排序
之前很多很多紫书上的东西我都忘了…… 抄题解的后果…… 做了一下裸题 https://vjudge.net/problem/UVA-10305 拓扑排序还可以来判环 #include<bits/ ...
- 关于最小生成树,拓扑排序、强连通分量、割点、2-SAT的一点笔记
关于最小生成树,拓扑排序.强连通分量.割点.2-SAT的一点笔记 前言:近期在复习这些东西,就xjb写一点吧.当然以前也写过,但这次偏重不太一样 MST 最小瓶颈路:u到v最大权值最小的路径.在最小生 ...
- Poj 2367 Genealogical tree(拓扑排序)
题目:火星人的血缘关系,简单拓扑排序.很久没用邻接表了,这里复习一下. import java.util.Scanner; class edge { int val; edge next; } pub ...
- 2016"百度之星" - 初赛(Astar Round2A)HDU 5695 拓扑排序+优先队列
Gym Class Time Limit: 6000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total S ...
- Luogu P1113 杂务 【拓扑排序】 By cellur925
题目传送门 这题我们一看就知道是拓扑排序,然而在如何转化问题上花了大工夫,一个小时后最后还是无奈看了题解qwq. 显然我们可以对于每个任务,从他的前导任务到他连一条边,最后我们可以得到一个DAG.在这 ...
- Codeforces Round #460 (Div. 2)_D. Substring_[dp][拓扑排序]
题意:一个有向图,每个结点 被赋予一个小写字母,一条路径的value等与这条路径上出现次数最多的字母的数目,求该图的最大value 比赛时,用dfs超时,看官方题解用的dp和拓扑排序,a--z用0-2 ...
- DAG及拓扑排序
1.有向无环图和拓扑排序 有向无环图(Directed Acyclic Graph,简称DAG):拓扑排序指的对DAG一个有序的线性排列.即每次选出一个没有入度的节点,然后输出该点并将节点和其相关连的 ...
- HDU-2647 Reward(链式前向星+拓扑排序)
Reward Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
随机推荐
- vim字符串替换命令
呜呜老是忘. 这里记录一下,仅仅记录当中日经常使用的最多的命令. :%s/str1/str2/g 替换每一行中全部str1为str2 经常使用! :s/str1/str2/g 替换当前行全部str ...
- Codefoces 432 C. Prime Swaps(水)
思路:从前往后想将1调整好,在调整2....这样平均每次有五次机会调整,并且有相当一部分可能都用不到五次,能够一试.ac 代码: #include<iostream> #include&l ...
- 基于DM642 RAW采集格式的视频驱动开发及应用
摘 要:为解决C64X系列数字信号处理器(DSP)视频驱动不能应用于原始数据格式(RAW)采集格式的问题,设计了DM642和电耦合元件(CCD)高清传感器的数据传输接口,并分析.修改用于标准格式的视频 ...
- Unity3D游戏开发之粒子系统实现具体解释
今天为大家分享的是Unity3D中的粒子系统.粒子系统通经常使用来表现烟雾.云等高级效果.是一个十分注重制作技巧的部分.今天我们将以一个气泡的演示实例来一起学习怎样在Unity3D中使用粒子系统 ...
- POJ 1182 食物链(并查集)
题目链接 经过宝哥的讲解,终于对这种问题有了进一步的理解.根据flag[x]和flag[y]求flag[tx]是最关键的了. 0吃1,1吃2,2吃0. 假设flag[tx] = X; 那么X + fl ...
- WAS:启动服务后,server一会挂起。
有个WAS集成,其中一台因为linux系统异常需要重新安装,于是服务器停了:一会现场提报ERP系统访问不了. 查看了另外一个server后台日志,有一批webcontainer进程挂起,明显服务死了. ...
- 666 专题五 AC自动机
Problem A.Keywords Search d.n个关键字,1段描述,求描述中出现了多少关键字 s. c. /* ac自动机模板 n个关键字,1段描述,求描述中出现了多少关键字 */ #inc ...
- springboot web项目搭建
1.选择spring initializr 2.填写应用名称及设置相关配置,建议使用默认配置即可 3.选择相关技术,我们现在web技术 4.填写项目名称 5.项目文件结构如下 6.直接运行 java ...
- C++中volatile及编译器优化
首先看一下单词"volatile"的释义: volatile [ˈvɑlətl] adj. 易变的,不稳定的; (液体或油)易挥发的; 爆炸性的; 快活的,轻快的; 下边是&qu ...
- 【USACO06NOV】路障
[题目链接] 点击打开链接 [算法] 最短路 [代码] #include<bits/stdc++.h> using namespace std; #define MAXN 5000 #de ...