常用模板

本文深入解析了多种经典算法模板,包括素数判断、快速幂、最大公约数、大数运算、堆、桶排序、动态规划、图论等,提供了详尽的代码实现和实例说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模板

素数判断

int Isprime(int n)
{
	for(int i=2;i*i<=n;i++)
		if(n%i==0)	return 0;
	return 1;
}

素数打表

求n以内的素数,如果 i 不为素数就将a[ i ]设为1,否则就设为0。

#include<cstdio> 
#include<cstring>
#include<algorithm>
using namespace std;
int a[(int)1e8+5];
void prime(int n) 
{
	memset(a,0,sizeof(a));
	for(int i=2;i<=n;i++)
		for(int j=2;j*i<=n;j++)
			if(!a[i*j])	a[i*j]=!a[i*j];
	for(int i=2;i<=n;i++)
		if(!a[i])	printf("%-5d",i);
}
int main()
{
	int n;
	while(~scanf("%d",&n))
		prime(n);
	return 0;
}

快速幂

typedef long long LL;   //  视数据大小的情况而定

LL powerMod(LL x, LL n, LL m)  x的n次方,结果模m
{
    LL res = 1;
    while (n > 0){
        if  (n & 1) //  判断是否为奇数,若是则true
            res = (res * x) % m;
        x = (x * x) % m;
        n >>= 1;    //  相当于n /= 2;
    }
    return res;
}

最大公约数___欧几里得算法(GCD)

#include<cstdio>
int gcd(int a,int b)    // 返回a , b的最大公约数
{
	return !b?a:gcd(b,a%b);
}
int main()
{
	int a,b;
	while(scanf("%d %d",&a,&b)!=EOF)
		printf("%d\n",gcd(a,b));
	return 0;
}

大数加法

/*
	大数加法采用的是模拟的思想,就是利用数组来储存一个数的每一位 
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10000;
char s1[MAXN],s2[MAXN];
int n1[MAXN],n2[MAXN],sum[MAXN];
int main()
{
	int T;
	scanf("%d",&T);
	for(int k=1;k<=T;k++)
	{
		scanf("%s %s",s1,s2);//用字符串来储存两个大数 
		memset(n1,0,sizeof(n1));//初始化数组,让它们全为0 
		memset(n2,0,sizeof(n2));
		memset(sum,0,sizeof(sum));//初始化保存结果的数组 
		int len1=strlen(s1);//第一个数的长度 
		int len2=strlen(s2);//第二个数的长度 
		int j=0;
		for(int i=len1-1;i>=0;i--)//将第一个数的每一位都逆序赋值给第一个数组 
			n1[j++]=s1[i]-'0';
		j=0;	
		for(int i=len2-1;i>=0;i--)
			n2[j++]=s2[i]-'0';
		int len=len1>len2?len1:len2;//找出来两个数中比较长的那个数 
		int pre=0;//用来保存进位 
		for(int i=0;i<len;i++)//给sum赋值,要记得sum可能是大于9的,输出的时候要对10取余 
		{
			sum[i]=n1[i]+n2[i]+pre/10;	
			pre=sum[i];
		}
		if(pre>9)//保存最高位的是sum[len-1] ,如果大于9 ,结果的位数要加一 
		{
			sum[len]=pre/10;//取高位 
			len++;//位数 +1
		}
		int t=len;
		for(int i=len-1;i>=0;i--)	//去掉前置0 
		{
			if(sum[i]==0)	t--;//像 0001 + 3 这种,结果应该输出 4 而不是0004 
			else			break;
		}
		printf("Case %d:\n%s + %s = ",k,s1,s2);
		for(int i=t-1;i>=0;i--)		
			printf("%d",sum[i]%10);
		printf("\n");
		if(k!=T)	printf("\n");//最后一组数据不要空行 
	 } 
	return 0;
}

大数乘法

/*
	大数乘法: 
	
	运用模拟,两个数组来储存两个大数
	另外一个数组来保存运算结果	
	
	em....
	
*/
 
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10000;
char s1[MAXN],s2[MAXN];
int a[MAXN],b[MAXN],c[MAXN];
int main() 
{
	while(scanf("%s %s",s1,s2)!=EOF)
	{
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(c,0,sizeof(c));
		int len1=strlen(s1);//第一个数的长度 
		int len2=strlen(s2);//第二个数的长度 
		int i,j;
		for(i=len1-1,j=0;i>=0;i--)	a[j++]=s1[i]-'0';//用数组逆序保存第一个数 
		for(i=len2-1,j=0;i>=0;i--)	b[j++]=s2[i]-'0';//用数组逆序保存第二个数 
		for(i=0;i<len1;i++)		
			for(j=0;j<len2;j++)
				c[j+i]+=a[i]*b[j];//一定要 + *  
		int len=len1+len2;
		for(i=0;i<len;i++)//进行进位运算 
			if(c[i]>9)
			{
				c[i+1]+=c[i]/10;
				c[i]%=10;
			 } 
		int t=len;
		for(i=len-1;i>=0;i--)//去掉前置0 
			if(c[i]==0)	t--;
			else		break;
		for(i=t-1;i>=0;i--)//输出 
			printf("%d",c[i]);		
		printf("\n");
	}	
	return 0;
}

小根堆

#include<cstring>
template<typename item>
class smallest_heap{
    private:
        item heap[10001];
        int len;
    public:
        smallest_heap();
        void push(item const &);
        void pop();
        item top();
        int size();
        bool empty();

};

template<typename item>
smallest_heap<item>::smallest_heap(){
    len=0;
    memset(heap,0,sizeof(heap));
}

template<typename item>
void smallest_heap<item>::push(item const &n){
    heap[++len]=n;
    int son=len,father=son/2;
    while(heap[son]<heap[father] && father>=1){
        swap(heap[son],heap[father]);
        son=father,father=son/2;
    }
}

template<typename item>
void smallest_heap<item>::pop(){
    swap(heap[1],heap[len]);
    heap[len--]=0;
    int father=1,son=2;
    while(son<=len){
        if(son<len && heap[son]>heap[son+1]) son++;
        if(heap[father]>heap[son]){
            swap(heap[father],heap[son]);
            father=son,son=father*2;
        }else break;
    }
}

template<typename item>
item smallest_heap<item>::top(){
    return heap[1];
}

template<typename item>
int smallest_heap<item>::size(){
    return len;
}

template<typename item>
bool smallest_heap<item>::empty(){
    return len;
}

大根堆

#include<cstring>
template<typename item>
class largest_heap{
    private:
        item heap[10001];
        int len;
    public:
        largest_heap();
        void push(item const &);
        void pop();
        item top();
        int size();
        bool empty();

};

template<typename item>
largest_heap<item>::largest_heap(){
    len=0;
    memset(heap,0,sizeof(heap));
}

template<typename item>
void largest_heap<item>::push(item const &n){
    heap[++len]=n;
    int son=len,father=son/2;
    while(heap[son]>heap[father] && father>=1){
        swap(heap[son],heap[father]);
        son=father,father=son/2;
    }
}

template<typename item>
void largest_heap<item>::pop(){
    swap(heap[1],heap[len]);
    heap[len--]=0;
    int father=1,son=2;
    while(son<=len){
        if(son<len && heap[son]<heap[son+1]) son++;
        if(heap[father]<heap[son]){
            swap(heap[father],heap[son]);
            father=son,son=father*2;
        }else break;
    }
}

template<typename item>
item largest_heap<item>::top(){
    return heap[1];
}

template<typename item>
int largest_heap<item>::size(){
    return len;
}

template<typename item>
bool largest_heap<item>::empty(){
    return len;
    }

同时也可以支持自己编写的类,但须提供“<”或“>”的运算符重载,例如

class T{
    private:
        int a;
    public:
        bool operator<(T const &type){
            return a<type.a;
        }
};
smallest_heap<T> heap;

桶排序

例题:P1090 合并果子 - 洛谷
时间复杂度:O(n)

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int k,x,num,n1,n2,a1[30001],a2[30001],t[20001],w,sum;
int main()
{
    scanf("%d",&num);
    memset(a1,127/3,sizeof(a1));
    memset(a2,127/3,sizeof(a2));
    for (int i=1;i<=num;i++)
    {
        scanf("%d",&x);
        t[x]++;//桶
    }
    for (int i=1;i<=20000;i++)
    {
        while (t[i])//桶排序
        {
            t[i]--;
            a1[++n1]=i;
        }
    }
    int i=1,j=1;
    k=1;
    while (k<num)
    {
        if (a1[i]<a2[j])//取最小值
        {
            w=a1[i];
            i++;
        }
        else
        {
            w=a2[j];
            j++;
        }
        if (a1[i]<a2[j])//取第二次
        {
            w+=a1[i];
            i++;
        }
        else
        {
            w+=a2[j];
            j++;
        }
        a2[++n2]=w;//加入第二个队列
        k++;//计算合并次数
        sum+=w;//计算价值
    }
    printf("%d",sum);
}
  • 归并排序+逆序对
#include <iostream>
using namespace std;

int count = 0;//记录逆序对的个数
// 合并数组,排好序,然后在拷贝到原来的数组array
void MergeArray(int array[], int start, int end ,int mid, int temp[]) {
    int i = start;
    int j =  mid + 1;
    int k = 0;
    while (i <= mid && j <= end ) {
        if (array[i] <= array[j]) {
            temp[k++] = array[i++];
        }else {
            temp[k++] = array[j++];
            count += mid - i + 1;
        }
    }
    while (i <= mid) {
        temp[k++] = array[i++];
    }
    while (j <= end) {
        temp[k++] = array[j++];
    }
    for (int i = 0; i < k; i ++) {
        array[start + i] = temp[i];
    }
    
}
// 归并排序,将数组前半部分后半部分分成最小单元,然后在合并
void MergeSort(int array[], int start,  int end, int temp[]) {
    if(start < end) {
        int mid = (start + end)/ 2;
        MergeSort(array, start, mid, temp);
        MergeSort(array, mid + 1, end, temp);
        MergeArray(array, start, end, mid, temp);
    }
    
}
// 在这里创建临时数组,节省内存开销,因为以后的temp都是在递归李使用的。
void MergeSort(int array[], int len) {
    int start = 0;
    int end = len - 1;
    int *temp = new int[len];
    MergeSort(array, start, end, temp);
}

void PrintArray(int array[], int len) {
    for (int i = 0 ; i < len; ++i) {
        cout << array[i] << " " ;
        
    }
    cout << endl;
}

int main(int argc, const char * argv[]) {
    int array[] = {3,5,3,6,7,3,7,8,1};
    
    MergeSort(array, 9);
    PrintArray(array, 9);
    
    
    return 0;
}

动态规划

最长公共子序列(长度+打印路径)

算法导论p.223

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int  maxn=1009;
char a[maxn],b[maxn];
int path[maxn][maxn],dp[maxn][maxn];//path 记录路径 
 
void lcs(int i,int j)//打印路径 
{
	if(i==0||j==0)	return ;//结束标志,a或者b只要有一个找完了,就不在找了 
	if(path[i][j]==1)//path是1的时候输出这个字符 
	{
		lcs(i-1,j-1);//因为是从后往前找的 
		printf("%c",a[i-1]);//所以这句得写到递归函数下边 
	 } 
	else if(path[i][j]==2)
		lcs(i-1,j);
	else 
		lcs(i,j-1);
	return ;
}
 
int main()
{
	while(~scanf("%s %s",a,b))
	{
		memset(dp,0,sizeof(dp));
		int m=strlen(a);
		int n=strlen(b);
		for(int i=1;i<=m;i++)
			for(int j=1;j<=n;j++)
				if(a[i-1]==b[j-1])
				{
					dp[i][j]=dp[i-1][j-1]+1;
					path[i][j]=1;
				}
				else if(dp[i-1][j]>dp[i][j-1])
				{
					dp[i][j]=dp[i-1][j];
					path[i][j]=2;
				}
				else
				{
					dp[i][j]=dp[i][j-1];	
					path[i][j]=3;
				}
		
		lcs(m,n);		
		printf("\n"); 
//		printf("\n%d\n",dp[m][n]);//输出最长子序列的长度 
	}
	return 0;

最长递增子序列(长度+打印路径)

  • 问题描述:
    设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,…,akm>,其中k1<k2<…<km且aK1<ak2<…<akm。求最大的m值。
  • 第一种算法:转化为LCS问题求解
    设序列X=<b1,b2,…,bn>是对序列L=<a1,a2,…,an>按递增排好序的序列。那么显然X与L的最长公共子序列即为L的最长递增子序列。这样就把求最长递增子序列的问题转化为求最长公共子序列问题LCS了。
    最长公共子序列问题用动态规划的算法可解。设Li=< a1,a2,…,ai>,Xj=< b1,b2,…,bj>,它们分别为L和X的子序列。令C[i,j]为Li与Xj的最长公共子序列的长度。
    这可以用时间复杂度为O(n2)的算法求解,由于这个算法上课时讲过,所以具体代码在此略去。求最长递增子序列的算法时间复杂度由排序所用的O(nlogn)的时间加上求LCS的O(n2)的时间,算法的最坏时间复杂度为O(nlogn)+O(n2)=O(n2)。
  • 第二种算法:动态规划
    设f(i)表示L中以ai为末元素的最长递增子序列的长度。则有如下的递推方程:
    这个递推方程的意思是,在求以ai为末元素的最长递增子序列时,找到所有序号在L前面且小于ai的元素aj,即j<i且aj<ai。如果这样的元素存在,那么对所有aj,都有一个以aj为末元素的最长递增子序列的长度f(j),把其中最大的f(j)选出来,那么f(i)就等于最大的f(j)加上1,即以ai为末元素的最长递增子序列,等于以使f(j)最大的那个aj为末元素的递增子序列最末再加上ai;如果这样的元素不存在,那么ai自身构成一个长度为1的以ai为末元素的递增子序列。

只求长度的(java):

public void lis(float[] L)
  {
         int n = L.length;
         int[] f = new int[n];//用于存放f(i)值;
         f[0]=1;//以第a1为末元素的最长递增子序列长度为1;
         for(int i = 1;i<n;i++)//循环n-1次
         {
                f[i]=1;//f[i]的最小值为1;
                for(int j=0;j<i;j++)//循环i 次
                {
                       if(L[j]<L[i]&&f[j]>f[i]-1)
                              f[i]=f[j]+1;//更新f[i]的值。
                }
         }
         System.out.println(f[n-1]);            
  }

求长度并打印的:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=105;
int a[MAXN];
int dp[MAXN];
int n;
int vis[MAXN];
void dfs(int pos)//打印路径 
{
	if(pos==-1)	return  ;
	dfs(vis[pos]);
	printf(" %d",pos+1);//这里是正序输出编号(从1开始的) 
}
int main()
{
	while(~scanf("%d",&n)&&n)
	{
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		memset(dp,0,sizeof(dp));
		memset(vis,-1,sizeof(vis));
		int res=0;
		int pos=-1;
		
		for(int i=0;i<n;i++)
		{
			dp[i]=1;
			for(int j=0;j<i;j++)
				if(a[i]>a[j])
				{
					if(dp[i]<dp[j]+1)
					{
						dp[i]=dp[j]+1;
						vis[i]=j;//vis[i]=j 表示以a[i]为结尾的LIS的上一个元素是a[j]		
					}
				}	
			if(res<dp[i])
			{
				res=dp[i];
				pos=i;//找到LIS的最后一个结点 
			}
		}
		printf("The number is %d:",res);//输出LIS的长度 
		dfs(pos);
		printf("\n");
	}
	return 0;
}

图论

最小生成树

Kruskal

Kruskal基本算法:每次选取最短的边,看该边相连的两点是否在同一集合内,若在,则跳过,若不在,就把两个点合并,判断与合并都用并查集实现。
Kruskal的复杂度是O(ElogE),适合稀疏图。

/*
Kruskal算法求MST
*/
 
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<fstream>
using namespace std;
 
const int MAXN=505;//最大点数
const int MAXM=250005;//最大边数
int F[MAXN];//并查集使用  查找使用的,可以改为用set来记录在A中的结点(相关概念见算法导论)
 
struct Edge
{
    int u,v,w;
}edge[MAXM];//储存边的信息,包括起点/终点/权值
 
int tol;//边数,加边前赋值为0
 
void addedge(int u,int v,int w)
{
    edge[tol].u=u;
    edge[tol].v=v;
    edge[tol++].w=w;
}
 
bool cmp(Edge a,Edge b)//排序函数,边按照权值从小到大排序
{
    return a.w<b.w;
}
 
int Find(int x)
{
    if(F[x]==-1)
        return x;
    else
        return F[x]=Find(F[x]);//平均时间复杂度为常数级
}
 
int Kruskal(int n)//传入点数,返回最小生成树的权值,如果不连通返回-1
{
    memset(F,-1,sizeof(F));
    sort(edge,edge+tol,cmp);
    int cnt=0;//计算加入的边数
    int ans=0;
    for(int i=0;i<tol;i++)
    {
        int u=edge[i].u;
        int v=edge[i].v;
        int w=edge[i].w;
        int t1=Find(u);
        int t2=Find(v);
        if(t1!=t2)
        {
            ans+=w;
            F[t1]=t2;
            cnt++;
        }
        if(cnt==n-1)//当添加的边数已经为n-1(n为结点数)时表示最小生成树已形成
            break;
    }
    if(cnt<n-1)
        return -1;//不连通
    else
        return ans;
}
 
int main( )
{
    //freopen("in.txt","r",stdin);
    int T;
    cin>>T;
    int n;
    int c;
    while(T--)
    {
        cin>>n;
        tol=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                cin>>c;
                addedge(i,j,c);
            }
        }
        cout<<Kruskal(n)<<endl;
    }
    return 0;
}

prim算法

  • 例题
    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
    Input
    测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
    行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
    Output
    对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
    Sample Input
    3 3
    1 2 1
    1 3 2
    2 3 4
    1 3
    2 3 2
    0 100
    Sample Output
    3
    ?
#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f
int lowcost[110];//此数组用来记录当前最小生成树的子树到达其他结点的最小花费
int map[110][110];//用来记录第i个节点到其余n-1个节点的距离 
int visit[110];//用来记录最小生成树中的节点 
int city;
void prime()
{
    int min,i,j,next,mincost=0;
    memset(visit,0,sizeof(visit));//给最小生成树数组清零 
    for(i=1;i<=city;i++)
    {
        lowcost[i]=map[1][i];//初始化lowcost数组为第1个节点到剩下所有节点的距离 
    }
    visit[1]=1;//选择第一个点为最小生成树的起点 
    for(i=1;i<city;i++)
    {
        min=INF;
        for(j=1;j<=city;j++)
        {
            if(!visit[j]&&min>lowcost[j])//如果第j个点不是最小生成树中的点并且其花费小于min 
            {
                min=lowcost[j];
                next=j;//记录下此时最小的位置节点 
            }
        }
        if(min==INF)
        {
            printf("?\n");
            return ;
        }
        mincost+=min;//将最小生成树中所有权值相加 
        visit[next]=1;//next点加入最小生成树 
        for(j=1;j<=city;j++)
        {
            if(!visit[j]&&lowcost[j]>map[next][j])//如果第j点不是最小生成树中的点并且此点处权值大于第next点到j点的权值 
            {
                lowcost[j]=map[next][j];         //更新lowcost数组 
            }
        }
    }
    printf("%d\n",mincost);
}
int main()
{
    int road;
    int j,i,x,y,c;
    while(scanf("%d%d",&road,&city)&&road!=0)
    {
        memset(map,INF,sizeof(map));//初始化数组map为无穷大 
        while(road--)
        {
            scanf("%d%d%d",&x,&y,&c);
            map[x][y]=map[y][x]=c;//城市x到y的花费==城市y到想的花费 
        }
        prime();
    }
    return 0;
}

单源最短路径算法

Dijkstra算法

1.定义概览

Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。
问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)

2.算法描述

1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。
2)算法步骤:
a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
d.重复步骤b和c直到所有顶点都包含在S中。

模板:

const int INF=0x3f3f3f3f;
const int maxn=1200;

int dist[maxn],g[maxn][maxn],N;// dist[i]表示源结点到i的最小距离,g[i][j]表示图中结点i到j的路径代价
bool vis[maxn];

void dijkstra()
{
    for(int i=1;i<=N;i++)
        dist[i]=(i==1)?0:INF;// 初始化,以i = 1 作为源结点 
    memset(vis,0,sizeof(vis));

    for(int i=1;i<=N;i++)
    {
        int mark=-1,mindis=INF;
        for(int j=1;j<=N;j++)
        {
            if(!vis[j]&&dist[j]<mindis)
            {
                mindis=dist[j];
                mark=j;
            }
        }
        vis[mark]=1;

        for(int j=1;j<=N;j++)
        {
            if(!vis[j])
            {
                dist[j]=min(dist[j],dist[mark]+g[mark][j]);
            }
        }
    }
}

内存优化后的Dijkstra:

int dist[N], point[N], n, m;
bool vis[N];

std::vector<pair<int, int> > g[N];//g[i][j] = <fi, se> 为边(i , fi)的距离se;

void dijkstra()
{
    for(int i=1;i<=n;i++)
        dist[i]=(i==1)?0:INF;
    memset(vis,0,sizeof(vis));

    for(int i=1;i<=n;i++)
    {
        int mark=-1,mindis=INF;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&dist[j]<mindis)
            {
                mindis=dist[j];
                mark=j;
            }
        }
        vis[mark]=1;

        for(int j=0;j<g[mark].size();j++)
        {
            if(!vis[g[mark][j].fi])
            {
                dist[g[mark][j].fi]=min(dist[g[mark][j].fi],dist[mark]+g[mark][j].se);
            }
        }
    }
}

堆优化后的Dijkstra:

// 堆优化dijkstra

void dijkstra()
{
    memset(dist,63,sizeof(dist));
    dist[S]=0;
    priority_queue<pII> q; /// -距离,点
    q.push(make_pair(0,S));

    while(!q.empty())
    {
        pII tp=q.top(); q.pop();
        LL u=tp.second;
        if(vis[u]==true) continue;
        vis[u]=true;
        for(LL i=Adj[u];~i;i=edge[i].next)
        {
            LL v=edge[i].to;
            LL len=edge[i].len;
            if(vis[v]) continue;
            if(dist[v]>dist[u]+len)
            {
                dist[v]=dist[u]+len;
                q.push(make_pair(-dist[v],v));
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值