算法总结第二篇

本周初始拟定任务

	学会树的基础算法--最小生成树模板
	洛谷模板题链接:[P3366](https://www.luogu.org/problem/P3366)
#include<iostream>
#include<string.h>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=2e5+10;
int findx[maxn],res=0,N,M,sum=0;
struct node{//记录每一个节点的起始和终点,以及边的权值
    int x,y,value;
}my[maxn];
int check(int x){//判断两个节点是否连通,并查集思想
    if(x==findx[x])return x;
    else return findx[x]=check(findx[x]);
}
bool cmp(node x,node y){//将每一个边按照权重从小到大排顺序
    return x.value<y.value;
}
int kruskal(){//克鲁斯卡尔算法,prim(普里姆)算法还未开始学习
    for(int i=0;i<M;i++){
        int a=check(my[i].x);
        int b=check(my[i].y);
        if(a!=b){//不连通则进行相连,连的边数加一,否则则说明当前最小权值连通之后构成了环,故不连
            findx[a]=b;
            res+=my[i].value;
            sum++;
        }
        if(sum==N-1)return res;//直到连的边等于节点的个数减1退出程序,此时已构成最小生成树
    }
    return -1;
}
int main(){
    cin>>N>>M;
    for(int i=0;i<M;i++)
    scanf("%d%d%d",&my[i].x,&my[i].y,&my[i].value);
    for(int i=0;i<=N;i++)findx[i]=i;
    sort(my,my+M,cmp);
    if(kruskal()==-1)cout<<"org";
    else cout<<res;
    return 0;
}

	学会图的基础算法--最短路基本模板,以及最短路的堆优化
	洛谷模板题链接:[P4779](https://www.luogu.org/problem/P4779)		
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=2e9+3;
int next[200010],head[200010],val[200010],to[200010],T;
bool vis[100010];
struct node{
	int x,v;
	node(int xx,int vv){
	    x=xx;v=vv;
	}
	bool operator <(const node p)const{//重载运算符<,用来优先队列的初始化
	    return v>p.v;//按照权重最大的排在最上面
	}
};
inline void addbian(int x,int y,int z){
    next[++T]=head[x];//next数组表示与当前起点相同的下一条边在哪
    head[x]=T;//head数组指的是当前起点是在第几次输入的
    to[T]=y;//to代表起点对应的终点是哪个节点
    val[T]=z;//记录第T条边的权值
}
int main(){
	int N,M,S,a,b,c;
	int dis[100010];
    cin>>N>>M>>S;
	for(int i=1;i<=N;i++)dis[i]=maxn;//先将起点到每一个节点的距离都设置为很大,以此来更新最短路径
	for(int i=0;i<M;i++){
        scanf("%d%d%d",&a,&b,&c);
        addbian(a,b,c);
	}
	dis[S]=0;//将起点到自己更新为0
	priority_queue<node>my;//定义优先队列,优先队列的存储结构为树形结构,重载之后大的在上,小的在下
	my.push(node(S,0));
	while(!my.empty()){//每一轮更新之后最上面的均是最短路径对应的终点节点,以此来更新下一个与终点节点的最短路径
        int now=my.top().x;
        my.pop();
        if(vis[now])continue;
        vis[now]=1;
        for(int i=head[now];i;i=next[i]){//i代表起点相同的节点--->下一个终点,更新该中的时对应的最短路
            if(dis[now]+val[i]<dis[to[i]]&&!vis[to[i]]){//判断是否满足更新
                dis[to[i]]=dis[now]+val[i];
                my.push(node(to[i],dis[now]+val[i]));
            }
        }
	}
	for(int i=1;i<=N;i++){
        if(dis[i]==maxn)printf("2147483647 ");//这个是上一个弱化版要求输出的值,所以没改
        else
		    printf("%d ",dis[i]);
	}
	return 0;
}

多元最短路模板:(没找到模板题,有一道题用到了多元最短路,主要是Floyd算法)
树网的核:[牛客竞赛](https://ac.nowcoder.com/acm/contest/1113/G)
#include<iostream>
#include<algorithm>
using namespace std;
int n,s,floyd[310][310],dis,res=1e8;
int main(){
    int x,y,z;
    cin>>n>>s;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i!=j)
                floyd[i][j]=1e8;
        }
    }
    for(int i=1;i<n;i++){//存邻阶矩阵
        cin>>x>>y>>z;
        floyd[x][y]=z;
        floyd[y][x]=z;
    }
    for(int k=1;k<=n;k++)
	 for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++)
	       floyd[i][j]=min(floyd[i][k]+floyd[k][j],floyd[i][j]);//根据邻接矩阵的值进行节点之间最短路径的更新
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
             if(floyd[i][j]<=s){
                 dis=0;
                 for(int k=1;k<=n;k++){
                     dis=max(dis,(floyd[k][i]+floyd[k][j]-floyd[i][j])/2);
                 }
                 res=min(res,dis);
             }
        }
    }
    cout<<res;
    return 0;
}

二叉排序数的实现:
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=3e5+10;
int T=1,n;
struct NODE{
    int lc,rc,v,cnt;//cnt记录相同数字时有多少个
}node[N];
void build(int now,int val){//当前节点位置,值,从小到大排序,如果从大到小只需要将lc改成rc即可
    if(!node[now].v){node[now].v=val,node[now].cnt++;return;}//如果当前节点为赋值,则为其赋值
    if(node[now].v==val){node[now].cnt++;return;}//如果值相等,则使cnt计数加1就行
    if(node[now].v<val){
        if(!node[now].rc)node[now].rc=++T;//如果当前节点左孩子为申请,则进行申请
        build(node[now].rc,val);//对左孩子进行赋值
    }else {
        if(!node[now].lc)node[now].lc=++T;
        build(node[now].lc,val);
    }
}
void print(int now){
    if(!node[now].v)return ;
    if(node[now].lc)print(node[now].lc);//一直遍历到最左边的孩子
    for(int i=0;i<node[now].cnt;i++)cout<<node[now].v<<" ";//输出当前节点对应的值的个数
    if(node[now].rc)print(node[now].rc);//然后遍历右孩子
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x;
        build(1,x);//从节点1开始插入
    }
    print(1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值