ディレクトリ
トポロジカル整列上のI、
1.定義
DAG(有向非巡回グラフ、有向非巡回グラフ)のいずれかのために、図のすべてのノードシーケンス場合、及びいずれかの側のために\((U、V)\) 、配列中のUの位置でありますVの位置が前に、私たちは、トポロジカル整列(トポロジカルソート)と呼ばれるトポロジカル注文プロセスを求めて、シーケンス・トポロジー・マップ(トポロジカルオーダー)のために、このようなシーケンスを呼び出します。
2.実装プロセス
私たちは、それぞれの拡張機能で、各ノードにキューからエンキュー0度ノード、マイナス1に隣接するドットの各延長に描画されます。0であるに隣接するノードを展開する場合は、我々はチームにこのノードを持っています。
トポロジカル整列の第二に、アプリケーション
トポロジカルソートは、問題のいずれかの種類を解決することができますか?
図中のループがあるかどうか1。
そこ図環場合、トポロジカルソートした後、特定のノードのリングは0ではない、そしてこれらのノードは、キューに挿入することができません。
これによると、我々はリングの性質を決定することができます。
void topo_sort(){
queue<int> q;
for(int i=1;i<=n;i++){
if(!in[i]) q.push(i);
}
while(!q.empty()){
int u=q.front();q.pop();
ans[++cnt]=u;
for(int e=first[u];e;e=next[e]){
int v=go[e];
if(!--in[v]) q.push(v);
}
}
}
//在main函数内
if(cnt!=n) printf("exist");
for(int i=1;i<=n;i++) if(!ans[i]) printf("exist");
//两种判环方式
2.要素間の関係を説明
例1:P1113の雑用
エントリーのタイトル。すべての残骸はこの1つの破片の開始前に完了することになる、と破片完了時間が最大時間によって決定された後にのみ破片を過ごしました。
その上に最大時間ごと更新限り。
#include<bits/stdc++.h>
#define N 100100
using namespace std;
int in[N],cost[N],dist[N];
int n,first[N],next[N],go[N],tot;
inline void add_edge(int u,int v){
next[++tot]=first[u];
first[u]=tot;
go[tot]=v;
}
inline void toposort(){
queue<int> q;
for(int i=1;i<=n;i++){
if(!in[i]) q.push(i);
dist[i]=max(dist[i],cost[i]);
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int e=first[u];e;e=next[e]){
int v=go[e],w=cost[v];
in[v]--;
dist[v]=max(dist[v],dist[u]+w);
if(!in[v]) q.push(v);
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1,id,len,must;i<=n;i++){
scanf("%d%d",&id,&len);
cost[id]=len;
while(scanf("%d",&must)&&must){
add_edge(must,id);
in[id]++;
}
}
toposort();
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,dist[i]);
printf("%d",ans);
return 0;
}
例2:P3116 [USACO15JAN]任命会議の時間
動的プログラミングの+トポロジカルソート、被験体は、最小時間がエンドポイントに共通の出発点から得られたnは1であり、必要です。だから我々は、uがVノードは、過ごすことができたときに位相幾何学の点から1を並べ替えを開始することができcb[e]
、ce[e]
Vへのuの時間を。ダイナミックな伝達方程式if(f[u][i]) f[v][i+cb[e](ce[e])]=1
。fはノードを表し、ここで、iは、uは時間がかかり到達することができます。
しかし、ノード0の度合いは、他の浸透ノード0が存在しない場合、一部のノードがチームになりませんがあり、必ずしも一つだけではありません。この時点で、我々は最初のようにゼロのみ1度のことを保証する、唯一の他のトポロジカルソートを行う必要があります。
#include<bits/stdc++.h>
using namespace std;
int n,m,tot,in[100010];
int first[100010],next[100010],go[100010],cb[100010],ce[100010];
int stb[110][20010],ste[110][20010];
inline void add_edge(int u,int v,int c,int d){
next[++tot]=first[u];
first[u]=tot;
go[tot]=v;
cb[tot]=c;ce[tot]=d;
}
inline void Deal_first(){
queue<int>q;
for(int i=2;i<=n;i++) if(in[i]==0) q.push(i);
while(!q.empty()){
int u=q.front();
q.pop();
for(int e=first[u];e;e=next[e]){
int v=go[e];
if(!--in[v]) q.push(v);
}
}
}
inline void Topo_sort(){
queue<int> q;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
for(int e=first[u];e;e=next[e]){
int v=go[e];
if(!--in[v]) q.push(v);
for(int i=0;i<=10001;i++){//动态规划
if(stb[u][i]) stb[v][i+cb[e]]=1;
if(ste[u][i]) ste[v][i+ce[e]]=1;
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,u,v,c,d;i<=m;i++){
scanf("%d%d%d%d",&u,&v,&c,&d);
add_edge(u,v,c,d);
in[v]++;
}
Deal_first();
stb[1][0]=ste[1][0]=1;
Topo_sort();
for(int i=0;i<=10000;i++){
if(stb[n][i]&&ste[n][i]){
printf("%d",i);
return 0;
}
}
printf("IMPOSSIBLE");
return 0;
}
例3:P3243 [HNOI2015]料理の、
これは純粋にトポロジカル整列の問題のように見えます。限り、我々は小さなスタックルートでそれを維持するよう、それぞれがまだそれに他の料理を更新するために、料理の最小数を取っていませんか?あなたは、物事はそう単純ではないでしょう紫色の質問は、まあ、ただのラベルを見ています。実際に、我々は簡単にカウンタ例ことができる:
\ [条件<5,1>、<3,4> \]
この時点でキューに入れ、その後最初の3を取るように、唯一3,5- 0度を起動4 {4,5}に、
4、5後に採取し、そして最後に取り出しになります。これは、順序を与えた(3,4,5,1)、明らかに答えは(5,1,3,4)です。
その理由は、被験者が先の地点の小さい条件のために必要な数を確保するために必要であること、最適な戦略は背面に大きな数字で、この時間を作ることです。したがって、我々は、抗図を作成することができ、各待ち行列は、各シリアル番号小さい上部面を確保するのに要する最大のシーケンス番号を更新します。読まれる対象データの数に加えて、毎回の初期化を覚えています。
#include<bits/stdc++.h>
#define N 100010
using namespace std;
int t,m,n,tot,flag,in[N],ans[N];
int first[N],next[N],go[N],cnt;
inline void add_edge(int u,int v){
next[++tot]=first[u];
first[u]=tot;
go[tot]=v;
}
inline void toposort(){
priority_queue<int> q;
for(int i=1;i<=n;i++) if(!in[i]) q.push(i);
while(!q.empty()){
int u=q.top();q.pop();
ans[++cnt]=u;
for(int e=first[u];e;e=next[e]){
int v=go[e];
in[v]--;
if(!in[v]) q.push(v);
}
}
}
inline void clear_data(){
tot=0;flag=0;cnt=0;
memset(first,0,sizeof(first));
memset(next,0,sizeof(next));
memset(go,0,sizeof(go));
memset(in,0,sizeof(in));
memset(ans,0,sizeof(ans));
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
clear_data();
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
in[u]++;
add_edge(v,u);
}
toposort();
if(cnt<n) printf("Impossible!\n");
else{
for(int i=cnt;i>=1;i--) printf("%d ",ans[i]);
printf("\n");
}
}
return 0;
}
実施例4:P1983グレーディングステーション
学年部門に寄せられる質問の最小数を検索します。ドッキングステーションポイントがステーション(大きい点レベルの小さいレベル)をドッキングように列車が、唯一の移植されたよりも大きいステーションのレベルで停止します。層の数から計算DAG図は、トポロジカルソートの答えです。
#include<bits/stdc++.h>
#define N 1020
using namespace std;
int n,m,h[N],vis[N],link[N][N],in[N];
int q[N],tot,ans,p;
inline void toposort(){
memset(vis,0,sizeof(vis));
do{//求DAG的层数
p=0;//p为节点度数为0的个数
for(int i=1;i<=n;i++) if(!in[i]&&!vis[i]) q[++p]=i,vis[i]=1;
for(int i=1;i<=p;i++)
for(int j=1;j<=n;j++)
if(link[q[i]][j]) in[j]--,link[q[i]][j]=0;
ans++;//不断累积层数
}while(p>0);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,s;i<=m;i++){
scanf("%d",&s);
memset(vis,0,sizeof(vis));
for(int j=1;j<=s;j++){
scanf("%d",&h[j]);
vis[h[j]]=1;
}
for(int j=h[1];j<=h[s];j++){//枚举所有列车可能经过的节点
if(!vis[j])//不停靠的节点
for(int k=1;k<=s;k++){
if(!link[j][h[k]]){//建立关系
in[h[k]]++,link[j][h[k]]=1;
}
}
}
}
toposort();
printf("%d",ans-1);
return 0;
}