拓撲排序+最小生成樹

由於上一節課的總結我沒有放上來,所以這次就放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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章