最短路 and 最小生成数 and 二分图[AcWing学习记录]

目录

  • 最短路
    • 单源最短路
      • 朴素Dijkstra
      • 堆优化Dijkstra
      • Bellman-Ford
      • spfa
    • 多源汇最短路
      • Floyd
  • 最小生成树
      • Prim
      • Kruskal
  • 二分图
      • 染色法
      • 匈牙利算法

最短路

单源最短路

n 为点数, m为边数
边权为正:朴素Dijkstra(n * n), 堆优化Dijstra算法(mlogn)。
边权为负:Bellman-Ford(n * m),spfa(平均o(m),最坏nm)。

朴素Dijkstra

用于稠密图。m 和 n * n 一个级别。

#include
/* ----------------------------------------
	存储方式:邻接矩阵(二维数组) 
	s 已经确认最短路的点。 
	① dist[1] = 0, dist[i] = inf;
	② for i : 0 ~ n 
		t <- 不在s 中的距离最近的点。
		s <- t 用t 更新其他所有点的距离。 
*///----------------------------------------
using namespace std;

const int N = 510;

int n , m;
int g[N][N];
int dist[N];
bool 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;
	return dist[n];
}

int main()
{
     
	scanf("%d%d", &n, &m);
	memset(g, 0x3f ,sizeof g);
	while(m --)
	{
     
		int a, b , c;
		scanf("%d%d%d",&a, &b, &c);
		g[a][b] = min(g[a][b], c);
	}
	int t = dijkstra();
	
	printf("%d\n", t);
	return 0;
} 

堆优化Dijkstra

用于稀疏图。m 和 n 一个级别。

#include
/* ----------------------------------------
	堆优化 
	存储方式:邻接表
	s 已经确认最短路的点。 
	① dist[1] = 0, dist[i] = inf;
	② for i : 0 ~ n 
		t <- 不在s 中的距离最近的点。
		s <- t 用t 更新其他所有点的距离。 
*///----------------------------------------
using namespace std;

typedef pair<int , int> PII;

const int N = 1000010;

int n , m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool st[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);
	dist[1] = 0;
	
	priority_queue<PII, vector<PII>,greater<PII> >heap;
	heap.push({
     0, 1});
	
	while(heap.size())
	{
     
		auto t = heap.top();
		heap.pop();
		
		int ver = t.second ,distance = t.first;
		if(st[ver]) continue;
		else st[ver] = true;
		
		for(int i = h[ver]; i != -1;i = ne[i])
		{
     
			int j = e[i];
			if(dist[j] > distance + w[i])
			{
     
				dist[j] = distance + w[i];
				heap.push({
     dist[j], j});
			}
		}
	}
	
	if(dist[n] == 0x3f3f3f3f) return -1;
	return dist[n];
}

int main()
{
     
	scanf("%d%d", &n, &m);
	
	memset(h, -1, sizeof h);
	
	while(m --)
	{
     
		int a, b , c;
		scanf("%d%d%d",&a, &b, &c);
		add(a, b ,c); 
	}
	
	int t = dijkstra();
	
	printf("%d\n", t);
	return 0;
} 

Bellman-Ford

#include
#include
#include

using namespace std;

const int N = 510, M = 10010;

int n , m , k;
int dist[N], backup[N];

struct Edge{
     
    int a , b , w;
}edges[M];

int Bellman_Ford()
{
     
    memset(dist, 0x3f , sizeof dist);
    dist[1] = 0;
    
    for(int i = 0;i < k;i ++)
    {
     
        memcpy(backup, dist, sizeof dist);
        for(int j = 0;j < m;j ++)
        {
     
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            dist[b] = min(dist[b], backup[a] + w);
        }
    }
    
    if(dist[n] >= 0x3f3f3f3f / 2) return -1;
    return dist[n];
}

int main()
{
       
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 0;i < m;i ++)
    {
     
        int a, b ,w;
        scanf("%d%d%d", &a,&b,&w);
        edges[i] = {
     a, b, w};
    }
    
    int t = Bellman_Ford();
    
    if(t == -1)puts("impossible");
    else printf("%d\n", t);
    return 0;
}

spfa

#include
/* ----------------------------------------
    spfa
*///----------------------------------------
using namespace std;

typedef pair<int , int> PII;

const int N = 1000010;

int n , m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
queue<int> q;
bool st[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);
    dist[1] = 0;
    q.push(1);
    st[1] = true;
    
    while(q.size())
    {
     
        int 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])
                {
     
                	q.push(j);
                	st[j] = true;
				}
            }
        }
    }
    
    
	if(dist[n] == 0x3f3f3f3f) return -1;
	return dist[n];
}

int main()
{
     
	scanf("%d%d", &n, &m);
	
	memset(h, -1, sizeof h);
	
	while(m --)
	{
     
		int a, b , c;
		scanf("%d%d%d",&a, &b, &c);
		add(a, b ,c); 
	}
	
	int t = spfa();
	
	if(t == -1)puts("impossible");
	else printf("%d\n", t);
	return 0;
} 

多源汇最短路

Floyd

Floyd(n * n * n)算法

#include
#include
#include

using namespace std;

const int N = 210, INF = 1e9;

int n , m , Q;
int d[N][N];

void floyd()
{
     
	for(int k = 1;k <= n;k ++)
		for(int i = 1;i <= n;i ++)
			for(int j = 1;j <= n;j ++)
				d[i][j] = min(d[i][j] , d[i][k] + d[k][j]);
}

int main()
{
     
	scanf("%d%d%d", &n, &m, &Q);
	
	for(int i = 1;i <= n;i ++)
		for(int j = 1;j <= n;j ++)
			if(i == j)d[i][j] = 0;
			else d[i][j] = INF;
			
	while(m --)
	{
     
		int a , b, w;
		scanf("%d%d%d", &a , &b ,&w);
		
		d[a][b] = min(d[a][b], w);
	}
	
	floyd();
	while(Q --)
	{
     
		int l , r;
		scanf("%d%d", &l, &r);
		if(d[l][r] >= INF / 2)puts("impossible");
		else printf("%d\n", d[l][r]);
	}
	return 0;	
} 

最小生成树

朴素版本Prim(n ^ n),堆优化(mlogn)
Kruskal(mlogm)

Prim


Kruskal


二分图

染色法(n + m), 匈牙利算法(nm, 实际运行时间远小于nm)

染色法


匈牙利算法


你可能感兴趣的:(算法)