最小生成树练习(最短路径练习1)

  • 终于考完试了,追赶一下葛葛的进度,今天复习一下最小生成树的内容,说是最小生成树,但其实蛮多最短路径的问题的,所以就一块练习一下。

P1339 [USACO09OCT]Heat Wave G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题解: 

  • 模板题了,算是迪杰斯特拉的,我直接上版子,虽然很多时候我也想多对一个算法思考一会,可最近真的是在赶进度吧,算是,所以重复的代码我不想敲,所以我直接上模板

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//淼淼专属------///不要查重不要查重
#define for(i,a,b)for(int i=a;i<=b;i++)
#define rfor(i,a,b)for(int i=a;i>=b;i--)
using namespace std;
const int N = 2505;
const int INF = 0x3f3f3f3f;
int n, m;
int vis[N];
int dis[N];
int mp[N][N];
int s,t;
void init() {
    for (i,1,n) {
        for (j,1,n) {
            mp[i][j] = INF;
        }
    }
}
// Dijstra的模板
void Dijstra() {
	memset(vis, 0, sizeof(vis));
	memset(dis, INF, sizeof(dis));
	dis[s] = 0;
	for (i,1,n)
	{
		int MIN = INF;
		int index = -1;
		for (j,1,n)
		{
			if (vis[j] == 0 && dis[j] < MIN)
			{
				MIN = dis[j];
				index = j;
			}
		}
		if (index == -1)//已经没有比它小的点了
			break;
		vis[index] = 1;
		for (j,1,n)
		{
			if (vis[j] == 0 && dis[index] + mp[index][j] < dis[j] && mp[index][j] != INF)
				dis[j] = dis[index] + mp[index][j];
		}
	}
}
int main()
{
	cin >> n >> m >> s >> t;
	int x, y, z;
	init();
	//剩下的无非就是建一张图
	for (i, 1, m) {
		cin >> x >> y >> z;
		mp[x][y] = mp[y][x] = min(mp[x][y], z);
	}
	Dijstra();
	cout << dis[t] << endl;
}

 P1396 营救 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

代码如下:(正好水一下快读模板) 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//淼淼专属------///不要查重不要查重
#define for(i,a,b)for(int i=a;i<=b;i++)
#define rfor(i,a,b)for(int i=a;i>=b;i--)
using namespace std;
const int N = 2505;
const int INF = 0x3f3f3f3f;
int n, m, k, s;
int t;
int a[30000];
int fa[30000];
int cnt = 0;

int Find(int x) {
    if (x == fa[x]) {
        return x;
    }
    return fa[x] = Find(fa[x]);
}
struct node {
    int x;
    int y;
    int w;
    bool operator<(node p)const {
        return w < p.w;
    }
}e[100100];
void init() {
    for (i,1,n) {
        fa[i] = i;
    }
}
//void hebing(int x, int y) {
//    if (Find(x) != Find(y)) {
//        x = fa[y];
//    }
//}
inline int read()
{
    char c = getchar(); int x = 0, s = 1;
    while (c < '0' || c > '9') { if (c == '-') s = -1; c = getchar(); }//是符号
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }//是数字
    return x * s;
}
int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);//加速器
    n = read();
    m = read();
    s = read();
    t = read();
    init();
    for (i,1,m) {
        e[i].x = read();
        e[i].y = read();
        e[i].w = read();
        cnt++;
    }
    sort(e + 1, e + cnt + 1);
    for (i,1,m) {
        int xx = Find(e[i].x);
        int yy = Find(e[i].y);
        if (xx != yy) {
            fa[xx] = yy;
        }
        if (Find(s) == Find(t)) {
            cout << e[i].w << endl;
            return 0;
        }
    }
    
}

 P1342 请柬 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题意:

  • 输出最小费用=输出最小生成树(这么做之后人傻了)原来是要用Dijstral+堆优化来做呀,呜呜呜!(SPFA也可以当然),正好可以介绍一下这个优化的算法。
  • 堆优化利用到了优先队列,而这个题的话需要用最短路径算法计算两遍,然后统计即可。

 借鉴大佬们的代码->

#include
#include
#include
#include
#include
#define INF  0x3f3f3f3f
using namespace std;
const int N = 3000000;
int n, m;
int h1[N], h2[N];
int s1, s2;
struct node {
	int next;
	int to;
	int dis;
}e1[N], e2[N];
int vis1[N], vis2[N]; 
long long dis1[N], dis2[N];
 
void add1(int x, int y, long long w)
{
	e1[++s1].dis = w;
	e1[s1].next = h1[x];
	e1[s1].to = y;
	h1[x] = s1;
}

void add2(int x, int y, long long w)
{
	e2[++s2].dis = w;
	e2[s2].next = h2[x];
	e2[s2].to = y;
	h2[x] = s2;
}

void dij1(int start)
{
	priority_queue  > q;
	memset(dis1, INF, sizeof(dis1));
	memset(vis1, 0, sizeof(vis1));
	q.push(make_pair(0, start));
	dis1[1] = 0;
	while (!q.empty())
	{
		long long k;
		int t = q.top().second;
		q.pop();
		if (vis1[t]) {
			continue;
		}
		vis1[t] = 1;
		for (int i = h1[t]; i; i = e1[i].next)
		{
			int j = e1[i].to;
			k = e1[i].dis;
			if (dis1[t] + k < dis1[j])
			{
				dis1[j] = dis1[t] + k;
				q.push(make_pair(-dis1[j], j));//距离最小的先弹出,也可以直接运算符重载
			}
		}
	}
}

void dij2(int start)
{
	memset(dis2, INF, sizeof(dis2));
	memset(vis2, 0, sizeof(vis2));
	priority_queue  > q;	
	q.push(make_pair(0, start));
	dis2[1] = 0;
	while (!q.empty())
	{
		long long k;
		int t = q.top().second;
		q.pop();
		if (vis2[t]) {//队首的这个点是否已经被扫描过
			continue;
		}

		vis2[t] = 1;
		for (int i = h2[t]; i; i = e2[i].next)
		{
			int j = e2[i].to;
			k = e2[i].dis;
			if (dis2[t] + k < dis2[j])
			{
				dis2[j] = dis2[t] + k;
				q.push(make_pair(-dis2[j], j));
			}
		}
	}
}

int main()
{
	cin >> n >> m;
	long long x, y, z;
	for (int i = 1; i <= m; i++)
	{
		cin >> x >> y >> z;
		add1(x, y, z);
		add2(y, x, z);
	}
	long long ans = 0;
	dij1(1);
	dij2(1);
	for (int i = 1; i <= n; i++)
	{
		ans += dis1[i] + dis2[i];
	}
	cout << ans << endl;
}

你可能感兴趣的:(淼淼的图论,淼淼的算法之路,算法,c++,图论)