拓扑排序+最小生成树

21 篇文章 0 订阅
5 篇文章 0 订阅
由于上一节课的总结我没有放上来,所以这次就放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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值