由於上一節課的總結我沒有放上來,所以這次就放l兩課吧。
1、拓撲排序:
拓撲排序就是指知道一個數據中兩個數據之間的前後關係,從而知道整個數據的具體順序。
士兵排序(網上找的)
問題描述:
有n個士兵(1≤n≤26),編號依次爲A、B、C,…… 隊列訓練時,指揮官要把一些士兵從高到矮依次排成一行。但現在指揮官不能直接獲得每個人的身高信息,只能獲得“p1比p2高”這樣的比較結果(p1,p2∈{‘A’,…,’Z’}),記爲p1>p2。例如A>B,B>D,F>D。士兵的身高關係如圖所示:
對應的排隊方案有三個:AFBD、FABD、ABFD
input:
第一行:一個整數n,k(k<=40) k表示k條關係
第2~k+1行:兩個字符x和y,表示x比y大
output:
一個只包含大寫字母的字符序列,表示其中一種排隊方案
input:
6 8
A C
C B
A E
F E
B D
A B
F A
D E
output:
FACBDE
具體算法是這樣的:
創新班22、23課總結 - 周正華 - 周正華的博客
先依照數據畫出一棵樹。然後就會發現有一些入度爲0(沒有點連向他)的。把那些點記在爲頭,同時記下所有點的入度,然後開始寬搜,找到一個點就把被那個點連向的所有點的入度-1,(即刪除該點),每找到找到一個入度爲0的就把它放進bfs的數組中,並且輸出。
#include <iostream>
#include <fstream>
using namespace std;
ifstream fin("sb.in");
ofstream fout("sb.out");
#define cin fin
#define cout fout
int n,k;
char x,y;
int din[26];
bool f[26][26];
int bfs[10001];
int main()
{
cin>>n>>k;
for(int i=0;i<k;i++)
{
cin>>x>>y;
f[x-'A'][y-'A']=1;
din[y-'A']++;
}
int head=0,last=-1;
for(int i=0;i<n;i++)
if(din[i]==0) last++,bfs[last]=i;
for(;head<=last;head++)
{
for(int i=0;i<n;i++)
if(f[bfs[head]][i])
{
din[i]--;
if(din[i]==0)
last++,bfs[last]=i;
}
cout<<char(bfs[head]+'A');
}
cout<<endl;
return 0;
}
2、最小生成樹
最小生成樹是指有若干個點,直到每兩個點之間的距離,求用若干條邊把這些點變成一個連通塊,並且要讓這些邊的和最小。
最小生成樹有兩種解法(Kruskal和Prim)
Kruskal:
這個算法基本就是貪心。每次都只找最小的邊,然後遇到環就不選,就這麼一直找下去,直到連完所有邊爲止。
具體做法是這樣的:
1 把所有距離按最小值排序
2 for循環搜一遍已排序的距離,並且加入邊(x,y)
3 如果邊(x,y)把這棵樹組成了環,那麼就不加這條邊
4 一直執行2,構成樹後退出
那麼如何證明每次選最小的就是正確的呢?
創新班22、23課總結 - 周正華 - 周正華的博客
現在所有黑色邊與線段A所連接組成的是一棵最小生成樹。但是現在來了一條邊B,由於我們之前一直去的是最小的邊,所以B一定比A小。那麼我們現在要證明的是選最小邊A比選B更優(或說是不差)。
假設選B比選A更優,那麼我們選B之後發現由於B比A大,導致這棵樹的所有邊的和比原來大,那麼就沒原來那麼優。
而B其實也有可能跟A一樣長,那麼我們選A和選B都能達到最優解。那既然這樣,我們選A也絕不會比選B差。所以我們每次選最小邊是最優解。
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
ifstream fin("Kruskal.in");
ofstream fout("Kruskal.out");
#define cin fin
#define cout fout
int n,m;
struct Tnode
{
int x,y;
int len;
};
Tnode a[1000001];
int fa[100001];
int ans=0;
bool cmp(Tnode x,Tnode y)
{
return x.len<y.len;
}
int u_f(int x)
{
int root=x;
while(root!=fa[root]) root=fa[root];
int t;
while(fa[x]!=root)
{
t=fa[x];
fa[x]=root;
x=t;
}
return root;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=0;i<m;i++)
cin>>a[i].x>>a[i].y>>a[i].len;
sort(a,a+m,cmp);
int fx,fy;
for(int i=0;i<m;i++)
{
fx=u_f(a[i].x);
fy=u_f(a[i].y);
if(fx!=fy)
{
fa[fy]=fx;
ans+=a[i].len;
cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].len<<endl;
}
}
cout<<ans<<endl;
return 0;
}
/*
Kruskal.in
5 10
1 2 7
1 3 6
1 4 9
1 5 7
2 3 10
2 4 8
2 5 3
3 4 4
3 5 6
4 5 15
Kruskal.out
2 5 3
3 4 4
1 3 6
3 5 6
19
*/
Prim:
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
ifstream fin("Prim.in");
ofstream fout("Prim.out");
#define cin fin
#define cout fout
int n,m;
struct Tnode
{
int x,y;
int len;
};
Tnode a[10001];
bool outside[1001];
int Min[1001];
int line[1001][1001];
int ans=0;
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
cin>>a[i].x>>a[i].y>>a[i].len;
line[a[i].x][a[i].y]=a[i].len;
line[a[i].y][a[i].x]=a[i].len;
}
for(int i=2;i<=n;i++)
Min[i]=line[i][1];
Min[0]=1000000;
outside[1]=0;
for(int i=1;i<=n;i++)
{
int now=0;
for(int j=1;j<=n;j++)
if(Min[j]<Min[now] && outside[j])
now=j;
outside[now]=0;
ans+=Min[now];
for(int j=1;j<=n;j++)
if(line[j][now]<Min[j] && outside[j])
Min[j]=line[j][now];
}
cout<<ans<<endl;
return 0;
}