拓步排序
相关概念
拓步排序:对一个有向无环图G进行拓扑排序,是将G中所有顶点排成 一个线性序列,使得图中任意丏对顶点u和v,若 边< u, v >∈E(G),则u在线性序列中出现在v 之前。通常, 这样的线性序列称为满足拓扑次序的序列,简称拓扑序列。
如果图中存在环,则无法进行拓扑排序。
BFS 的算法流程:
(1)
在图中选择所有入度为零的顶点,加入队列。
(2)
从队列中取出一个点,删除该点及其所有出边
(
对应点的
入度
-1)
。
重复
(1)
和
(2)
,直到队列为空,如果图中仍有入度不为
0
的顶
点表示图中包含有向回路。
题目连接:
Genealogical tree
code:
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
vector<int> ve[110];//存图
int in[110];.//入度
int cnt;
int ans[110]; //存答案
int n;
int main()
{
queue<int> q;
cin>>n;
int x;
for(int i=1;i<=n;i++){
while(cin>>x&&x){
ve[i].push_back(x);//建图 入度+1
in[x]++;
}
}
//初始化队列
for(int i=1;i<=n;i++){
if(!in[i]){
q.push(i);
ans[cnt++]=i;//入度为0的点放在答案数组里面
}
}
//队列里面都是入度为0 的点
while(q.size()){
int u=q.front();
q.pop();
//删除入度为0 的点所连接的边
for(int i=0;i<ve[u].size();i++){
int v=ve[u][i];
in[v]--;
if(!in[v]){//如果边的终点入度为0就加入
q.push(v);
ans[cnt++]=v;
}
}
}
for(int i=0;i<n;i++){
cout<<ans[i]<<" ";
}
return 0;
}
确定比赛名次
这个题不能随便输出,所以要用到优先队列,小的先输出。
记得是多输入,所以得初始化,只有存图的vector要初始化,入度数组最后一定是0,队列为空
code:
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int N=550;
vector<int> ve[N];
int in[N];
int n,m;
int cnt=0;
int ans[N];
void topo()
{
priority_queue<int,vector<int>,greater<int> > q;
for(int i=1;i<=n;i++){
if(!in[i]) q.push(i);
}
while(q.size()){
int t=q.top();
q.pop();
ans[cnt++]=t;
for(int i=0;i<ve[t].size();i++){
int v=ve[t][i];
in[v]--;
// if(in[v]<0) cout<<" &&&&"<<endl;
if(!in[v]) q.push(v);
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)){
cnt=0;
for(int i=1;i<=n;i++) ve[i].clear();//这一步别忘了
while(m--){
int u,v;
scanf("%d%d",&u,&v);
ve[u].push_back(v);
in[v]++;
}
topo();
printf("%d",ans[0]);
for(int i=1;i<cnt;i++){
printf(" %d",ans[i]);
}
puts("");
}
return 0;
}
产生冠军
思路:要明确这个题的题意,最后只能有一个冠军,说明讲string转为int 后 ,只能有一个入度为0.
这个题产不产生环都不无所谓的。
code:
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
using namespace std;
int cnt;
map<string,int> ma;//要记住map可以将字符串映射成数字
int in[2200];
int main()
{
int n;
while(~scanf("%d",&n)&&n){
cnt=1;
memset(in,0,sizeof in);
ma.clear();
string s,ss;
for(int i=1;i<=n;i++){
cin>>s>>ss;
if(!ma[s]) ma[s]=cnt++;
if(!ma[ss]) ma[ss]=cnt++;
in[ma[ss]]++;
}
int index=0;
for(int i=1;i<cnt;i++){
if(!in[i]) index++;
}
if(index==1) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
Reward
思路:这个题就是拓扑排序求深度,一个点可能有不同的深度,我们选择最深的作为它的深度
我写了俩个代码一个是链式前向星的存图方式,一个是邻接表
code:
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int N=2e4+10;
int in[N],depth[N];
int head[N],ne[N],e[N];
int a,b;
int n,m;
int cnt=0;
ll ans=0;
int index;//记录入度为0的点的个数
void add(int u,int v){
e[cnt]=v,ne[cnt]=head[u],head[u]=cnt++;
}
void topo(){
queue<int> q;
for(int i=1;i<=n;i++){
if(!in[i]){
index++;
q.push(i);
depth[i]=0;
}
}
while(q.size()){
// cout<<"**"<<endl;
int u=q.front();
q.pop();
ans+=depth[u];
for(int i=head[u];i!=-1;i=ne[i]){
int v=e[i];// u的终点
in[v]--;
if(!in[v]){
index++;
depth[v]=depth[u]+1;
q.push(v);
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)){//wa了半天才发现是是~没加
cnt=0;
ans=0;
index=0;
memset(head,-1,sizeof head);
for(int i=0;i<N;i++) in[i]=depth[i]=ne[i]=e[i]=0;
while(m--){
scanf("%d%d",&a,&b);
add(b,a);
in[a]++;
}
topo();
if(index==n) printf("%lld\n",ans+(ll)n*888);
else puts("-1");
}
return 0;
}
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N=2e4+10;
vector<int> ve[N];
int in[N],depth[N];
int a,b;
int n,m;
ll ans=0;
int index;//记录入度为0的点的个数
void topo(){
queue<int> q;
for(int i=1;i<=n;i++){
if(!in[i]){
q.push(i);
}
}
while(q.size()){
int t=q.front();
q.pop();
index++;
ans+=depth[t];
for(int i=0;i<ve[t].size();i++){
int v=ve[t][i];
in[v]--;
if(!in[v]){
depth[v]=depth[t]+1;
q.push(v);
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)){
ans=0;
index=0;
for(int i=1;i<=n;i++) in[i]=depth[i]=0,ve[i].clear();
while(m--){
scanf("%d%d",&a,&b);
ve[b].push_back(a);
in[a]++;
}
topo();
if(index==n) printf("%lld\n",ans+(ll)n*888);
else puts("-1");
}
return 0;
}
Ordering Tasks
思路:普通的拓扑排序
code:
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
int n,m;
vector<int> ve[110];
int in[110];
int ans[110];
int cnt;
void topo()
{
queue<int> q;
for(int i=1;i<=n;i++){
if(!in[i]) q.push(i);
}
while(q.size()){
int t=q.front();
q.pop();
ans[cnt++]=t;
for(int i=0;i<ve[t].size();i++){
int v=ve[t][i];
in[v]--;
if(!in[v]){
q.push(v);
}
}
}
}
int main()
{
while(cin>>n>>m&&(n+m)){
cnt=0;
for(int i=1;i<=n;i++) ve[i].clear();
while(m--){
int a,b;
cin>>a>>b;
ve[a].push_back(b);
in[b]++;
}
topo();
for(int i=0;i<cnt;i++) printf("%d ",ans[i]);
puts("");
}
return 0;
}