拓补排序+邻接表
拓补排序定义
需要在有向无环图中
所谓“拓扑排序”,是指将一个有向无环图G的所有顶点排成一个线性序列,使得有向无环图G的边集中的任意一条边<u,
v>,始终满足u出现在v的前面。
通常,这样的序列称为是“拓扑序列”。
拓扑排序算法基本思想
- 在有向无环图中找到一个没有前驱的节点(或者说是入度为0的节点)输出;
- 然后从图中将此节点删除并且删除以该节点为尾的弧;
- 如果所有节点都已输出,则程序结束;否则,返回步骤1;
例题1
题目描述:
有N个队参加比赛(1<=N<=500),队伍编号依次为1, 2, 3, …,
N,比赛结束后,裁判委员会要将所有参赛队伍依次排名,但现在裁判委员会只知道每场比赛的结果,比如P1赢P2,用P1
P2表示,则排名时P1应该在P2之前。现在,请你编程确定最终的全部排名。排名若不唯一,则编号小的队伍在前。
Input 4 3 1 2 2 3 4 3
Output 1 2 4 3
如果加上BFS使用队列处理入队列0入度点
解题代码:
#include <cstdio> #include <iostream> #include <cstring> using namespace std; #define ll long long
int cnt; int n,m; int head[510]; int inn[510]; struct node { int to; int next; }edge[200005];
void add_edge(int from,int to){ edge[++cnt].to=to; edge[cnt].next=head[from]; head[from]=cnt; inn[to]++; return ; }
int findzero(){ for(int i=1;i<=n;i++){ if(inn[i]==0){ inn[i]--; return i; } } return 0; }
int main(){ while(cin>>n>>m){ for(int i=0;i<=n;i++){ inn[i]=0; head[i]=-1; } cnt=0; for(int i=1;i<=m;i++){ int from,to; scanf("%d%d",&from,&to); add_edge(from,to); } int num=0; while(int cur=findzero()){ num++; if(num==n){ cout<<cur<<endl; break; } cout<<cur<<" "; for(int k=head[cur];~k;k=edge[k].next){ inn[edge[k].to]--; } } } return 0; }
|
例题二
题目描述:
临近春节,甘老板决定为每个员工发红包。
现在的问题是,每人发多少红包呢?要知道,很多员工提出了自己的要求,比如,胡承轩就提出他的红包应该比麻致远的大!
为了图吉利,甘老板决定为每名员工至少发888的红包,同时,他还希望能满足员工们提出的所有的要求,当然,最后是希望发出红包的总金额最少。
员工数:n<=10000 提出的要求:m<=20000
Input
Output
可以反向建图+DP思想(money)
解题代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define ll long long
int n,m; int cnt; int head[10010]; int inn[10010]; int money[10010]; struct node{ int to; int next; }edge[20010];
void add_edge(int from,int to){ edge[++cnt].to=to; edge[cnt].next=head[from]; inn[to]++; head[from]=cnt; return ; }
int findzero(){ for(int i=1;i<=n;i++){ if(inn[i]==0){ inn[i]--; return i; } } return 0; }
int main(){ while(cin>>n>>m){ for(int i=0;i<=n;i++){ head[i]=-1; inn[i]=0; money[i]=888; } cnt=0; for(int i=1;i<=m;i++){ int from,to; scanf("%d%d",&to,&from); add_edge(from,to); } ll ans=0; int num=0; while(int cur=findzero()){ num++; ans+=money[cur]; for(int k=head[cur];~k;k=edge[k].next){ int to=edge[k].to; inn[to]--; money[to]=max(money[to],money[cur]+1); } } if(num!=n){ cout<<"-1"<<endl; continue; } cout<<ans<<endl; }
return 0; }
|
邻接表存储表
回顾:STL中vector的经典应用-邻接表
struct edge{ int from, to, value; }
const int maxn = 10005;
vector<edge> Map[maxn];
|
若用普通二维数组存邻接表,则需要1e8的空间开销,而图中实际边数只有20000,则无疑会造成极大浪费(易超内存)。
for(int i=0; i<maxn; i++) Map[i].clear();
|
链式前向星(邻接表数组实现)

