常用算法模板总结1

朴素版Dijkstra算法 

核心思路:

1.循环n次,每次找到到起点距离最小且不在已确定集合中的的点

2.将找到的点放入集合中

3.用找到的点来更新其他所有未在集合之中的点

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m;
const int N = 510,M=1e5+10;
int g[N][N];
int dist[M],st[N];
int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    for(int i=0;i<n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
            {
                t=j;
            }
        }
        st[t]=true;
        for(int j=1;j<=n;j++)
        {
            dist[j]=min(dist[j],dist[t]+g[t][j]);
        }
    }
    if(dist[n]==0x3f3f3f3f) return -1;
    else    return dist[n];
}
int main()
{
    cin>>n>>m;
    memset(g,0x3f,sizeof g);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b]=min(g[a][b],c);
    }
    int t=dijkstra();
    cout<<t;
    return 0;
}

堆优化版的Dijkstra算法 

核心思路:

1.将起点放入队列中(优先队列,小数在前)

2.取出队列中的点来更新他这一条链表上的点,如果更新了,就将更新的点放入队列中

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int,int> PII;
const int N=2e5+10;
int h[N],e[N],w[N],ne[N],idx;
int n,m;
int st[N];
int dist[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    priority_queue<PII,vector<PII>,greater<PII>> q;//小根堆
    q.push({0,1});//0表示距离,1表示点的位置
    while(q.size())
    {
        auto t=q.top();
        q.pop();
        int ver=t.second,distance=t.first;
        if(st[ver]) continue;
        st[ver]=true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>w[i]+distance)
            {
                dist[j]=w[i]+distance;
                q.push({dist[j],j});
            }
        }
    }
    if(dist[n]==0x3f3f3f3f) return -1;
    else return dist[n];
}
int main()
{
    cin>>n>>m;
    memset(h, -1, sizeof h);
    while (m -- )
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    int t=dijkstra();
    cout<<t;
    return 0;
}

spfa算法

求最短路

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
int n,m;
const int N = 2e5+20;
int h[N],w[N],ne[N],e[N],idx;
bool st[N];
int dist[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa()
{
    memset(dist, 0x3f ,sizeof dist);
    queue<int> q;
    q.push(1);
    st[1]=true;
    dist[1]=0;
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                if(!st[j])
                {
                    st[j]=true;
                    q.push(j);   
                }
            }
        }
    }
   return dist[n];
}
int main()
{
    cin>>n>>m;
    memset(h, -1, sizeof h);
    while (m -- ){
        int a,b,c;
        cin>>a>>b>>c;
        add(a, b, c);
    }
    if(spfa()>0x3f3f3f/2)   cout<<"impossible";
    else cout<<dist[n];
    return 0;
}

求负环

 

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
int n,m;
const int N = 2e5+20;
int h[N],w[N],ne[N],e[N],idx;
bool st[N];
int dist[N];
int cnt[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
    memset(dist,0x3f,sizeof dist);
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        st[1] = true;
        q.push(i);
    }
    dist[1]=0;
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>n)    return true;
                if(!st[j])
                {
                    st[j]=true;
                    q.push(j);
                }
            }
        }
    }
    return false;
}
int main()
{
    cin>>n>>m;
    memset(h, -1, sizeof h);
    while (m -- ){
        int a,b,c;
        cin>>a>>b>>c;
        add(a, b, c);
    }
    if(spfa())   cout<<"Yes";
    else cout<<"No";
    return 0;
}

bellman_ford算法

核心思路:

用结构体来存边

1.循环k次,每次先将dist[ ]数组备份

2.在每次循环中更新更新距离,用起点到点A的距离加上A到B的距离

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510,M=1e5+10;
int n,m,k;
struct node
{
    int a,b,w;
};
int dist[N],bf[N];
node edge[M];
int bellman_ford()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    for(int i=1;i<=k;i++)
    {
        memcpy(bf,dist,sizeof dist);
        for(int j=1;j<=m;j++)
        {
            auto e=edge[j];
            dist[e.b]=min(dist[e.b],bf[e.a]+e.w);
        }
    }
    return dist[n];
}
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        edge[i]={a,b,c};
    }
    int t=bellman_ford();
    if(t>0x3f3f3f3f/2)  cout<<"impossible";
    else cout<<t;
    return 0;
}

prim算法求最小生成树 

核心思路:

1.初始化所有距离为正无穷

2.for(n次)

    {

                每次找到不在集合中的距离最小的点

                如果这个点的距离为正无穷,即这个点与已知集合不连通,即无法形成最小生成树

                否则:{

                                        将总路径加上这段距离

                                        将其放入集合中

                                         for()

                                        {        

                                                更新距离为到最小距离的点和本身距离的小值

                                        }

                             }        

     }

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510,INF=0x3f3f3f3f;
int n,m;
int g[N][N],dist[N];
bool st[N];
int prim()
{
    memset(dist,0x3f,sizeof dist);
    int res=0;
    for(int i=0;i<n;i++)
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {
            if(!st[j]&&(t==-1||dist[t]>dist[j]))
            t=j;
        }
        if(i&&dist[t]==INF) return INF;
        if(i)   res+=dist[t];
        st[t]=true;
        for(int j=1;j<=n;j++)
        {
            dist[j]=min(dist[j],g[t][j]);
        }
    }
    return res;
}
int main()
{
    cin>>n>>m;
    memset(g,0x3f, sizeof g);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b]=g[b][a]=min(g[a][b],c);
    }
    int t=prim();
    if(t==INF)  puts("impossible");
    else cout<<t;
}

二分

整数二分(如果在选择语句中mid+1则mid=l+r>>1;否则mid=l+r+1>>1

int l,r;
bool check(int x)//检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用
int bsearch_1(int l,int r)
{
	while(l<r)
	{
		int mid=l+r>>1;
		if(check(mid))	r=mid;
		else l=mid+1;	
	} 
	return l;
}	 
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用
int bsearch_2(int l,int r)
{
	while(l<r)
	{
		int mid=l+r+1>>1;
		if(check(mid))	l=mid;
		else r=mid-1;	
	}
	return l;
}

浮点数二分

//精确到小数点后x位 
int l,r;
double check(double x)
double bsearch(double l,double r)
{
	while(r-l>10^(-(x+2)))
	{
		double mid=(l+r)/2;
		if(check(mid))	r=mid;
		else l=mid;
	}
	return l;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑夜蔓蔓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值