由于上一节课的总结我没有放上来,所以这次就放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;
}