(有任何问题欢迎留言或私聊
Prim算法
POJ1258题目链接:传送门
prim算法的过程:
首先我用到的几个变量
int ar[N][N;//存图,ar[i][j]=x,表示i和j的距离,则ar[i][i]=0;
int dis[N];//dis[i]存的是起始点1形成的生成树中,点1到点i 还需要距离!
int vis[N];//表示i节点是否在生成树中
以a点为根节点,dis[i]存的是起始点1形成的生成树中,点1到点i 还需要的距离
-
1.刚开始a只和b和d相连,所以dis[b]=dis[2]=4,dis[h]=dis[8]=8。其他点还没有和a相连,所以dis[i]=INF无穷大。
-
2.选择dis最小的,就是dis[2],值为4,下标为2.然后把b加入生成树中。
-
3.因为b加入了a的生成树中,所以和b相连的点也就和a相连了。这时候来更新他们和a点的距离。
-
4.因为ar[b][c]=8,ar[b][h]=11,而dis[c]=INF,dis[h]=8。选择较小的值。所以,更新后,dis[c]=8,dis[h]还是8.
-
5.求解过程以此类推。因为一颗n个节点的树只有n-1条边,所以这个过程只执行n-1次。
-
6.对了,要注意,已经加入生成树的节点不要更新也不用询问是否加入生成树中。所以我用到了vis数组。vis[i]=1表示在生成树中,vis[i]=0表示不在生成树中。
AC代码:
#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 105;
int n, ans;
int ar[N][N;//存图,ar[i][j]=x,表示i和j的距离,则ar[i][i]=0;
int dis[N];//dis[i]存的是起始点1形成的生成树中,点1到点i 还需要的距离
int vis[N];//表示i节点是否在生成树中
void init() {//这里是初始化
ans = 0;
memset(ar, 0, sizeof(ar));
memset(dis, 0x3f, sizeof(dis));
}
void Prim() {
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n;++i) {
dis[i] = ar[1][i];
}
vis[1] = 1;//起点肯定在生成树中
for (int i = 1; i <= n; ++i) {
int L = INF, m = -1;//要找到最小的dis,所以L初始赋值为无穷大,来逐步找到最小的dis,m表示下标
for (int j = 1; j <= n; ++j) {//算法 进行n-1次
if (dis[j] < L&&vis[j] == 0) {//找不在生成树中的节点
L = dis[j];
m = j;
}
}
if (m == -1) break;
ans += L;
vis[m] = 1;//标记
for (int j = 1; j <= n; ++j) {
if (ar[m][j] < dis[j]&&vis[j] == 0) {//更新
dis[j] = ar[m][j];
}
}
}
printf("%d\n", ans);//最小生成树的权值
}
int main() {
while (~scanf("%d", &n)) {
init();
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
scanf("%d", &ar[i][j]);
}
}
Prim();
}
return 0;
}
Kruskal算法
POJ1861题目链接:传送门
kruskal上面的视频中有讲解。要用到并查集这个算法。
并查集qsc学姐也有讲,看他的视频就好了,讲的非常棒。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define iis std::ios::sync_with_stdio(false)
using namespace std;
typedef long long LL;
const int N = 1005;
const int INF = 0x3f3f3f3f;
int n, tot, ans, m, num;
int fa[N];
int Num[15005];
struct lp{//邻接表存图
int x,y;//x,y表示边的两个端点
int len;//边权值
friend bool operator<(const lp &a,const lp &b){//重载<,这样就可以用sort排序
return a.len<b.len;
}
}cw[15005];
inline void init(){
tot = 2;ans = num = 0;
for(int i = 0; i <= n; ++i) fa[i] = i;//并查集,初始每个节点的fa是他们自己
}
inline int Fi(int x){//递归求解每个点的根节点
return fa[x]==x? x: fa[x] = Fi(fa[x]);
}
inline int unsame(int x, int y){//x,y是否是联通
int p = Fi(x), q = Fi(y);
return p != q;
}
inline void Union(int x, int y){//把x和y联通
int p = Fi(x), q = Fi(y);
if(p == q)return;
fa[q] = p;
return;
}
void kru(){
sort(cw, cw + m);//排序,边权小的排在前面,其实就是贪心
int cnt = 0;//加入生成树中的边
for(int i = 0; i < m; ++i){
if(unsame(cw[i].x, cw[i].y)){//如果x和y不连通,就把这条边加入生成树中
cnt++;
Union(cw[i].x, cw[i].y);
Num[num++] = i;
ans = cw[i].len;
}
if(cnt == n-1){//一棵树有n-1条边
return;
}
}
}
int main(){
while(~scanf("%d%d", &n, &m)){
init();
for(int i = 0, x, y, z; i < m; ++i) {
scanf("%d%d%d",&x,&y,&z);
cw[i].x = x;
cw[i].y = y;
cw[i].len = z;
}
kru();
printf("%d\n%d\n", ans, num);
for(int i = 0; i < num; ++i){
int t = Num[i];
printf("%d %d\n", cw[t].x, cw[t].y);
}
}
return 0;
}
POJ1798-Truck History
题目链接:传送门
AC代码:
#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = 2005;
int n, ans;
char s[N][N];
int dis[N],ar[N][N];
int vis[N];
void Prim() {
ans = 0;
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n;++i) {
dis[i] = ar[1][i];
}
vis[1] = 1;
for (int i = 1; i < n; ++i) {
int L = INF,m = -1;
for (int j = 1; j <= n; ++j) {
if (dis[j] && dis[j] < L&&vis[j]==0) {
L = dis[j];
m = j;
}
}
if(m == -1) break;
ans += L;
vis[m] = 1;
for (int j = 1; j <= n; ++j) {
if (ar[m][j] < dis[j]&&vis[j] == 0) {
dis[j] = ar[m][j];
}
}
}
printf("The highest possible quality is 1/%d.\n", ans);
}
int getval(int x, int y){
int an = 0;
for(int i = 0; i <= 6; ++i){
if(s[x][i] != s[y][i])an++;
}
return an;
}
int main() {
while (~scanf("%d", &n)&&n) {
for(int i = 1; i <= n; ++i){
scanf("%s",s[i]);
}
for(int i = 1; i <= n; ++i) {
for(int j = 1;j <= n; ++j){
if(i == j) ar[i][j] = 0;
else ar[i][j] = getval(i, j);
}
}
Prim();
}
return 0;
}